You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
letp=newPromise((resolve,reject)=>{console.log(1);setTimeout(()=>{resolve('then');},3000);});letp1=newPromise();// TypeError: Promise resolver undefined is not a functionp.then(res=>console.log(1));// '1', 3s -> 'then'
// 原生letp=newPromise((resolve,reject)=>{resolve('成功');})p.then(null,// 或undefinederror=>console.log(error));// 无输出无报错// 自己实现的letp=new_Promise(resolve=>{resolve('成功');});p.then(null,error=>console.log(error));// onFullfilled is not a function
Promise几个简单示例:
这个实例可以得到Promise的以下特点:
new Promise
后会立即执行,并且接收一个必传
函数作为参数接收的函数中有2个参数
值需要使用
then
方法获取这个实例可以得到Promise的以下特点:
pending
,成功fullfilled
,拒绝rejected
,并且状态只能从pending
转变为fulfilled
或者rejected
,不可逆resolve
将状态转变为fulfilled
,reject
将状态转变为rejected
pending
转变为fulfilled
或者rejected
就不会再改变了1、根据前面的总结定义好初始结构
根据第二个示例我们可以看到
p3
中抛出错误也是被rejected
的,所以优化下结构:2、实现resolve、reject方法
在前面的示例中已经知道
promise
传入的函数接收2个参数,也就是resolve
和reject
,他们的作用就是改变promise
的状态。状态只能从
pending
转变为fullfilled
和rejected
,并且不可逆:根据示例可以看到调用
resolve
和reject
时可以传递参数,最后可以通过调用then
获取结果。3、实现then方法
因为
then
方法返回了promise
,而promise
上又有then
方法,所以可以链式调用,例如:先看下原生方法的执行结果:
new Promise
时接收2个参数,分别为将状态转变为fullfilled
和rejected
的回调函数。而then
方法也是接收2个参数,分别为promise
的成功和失败情况的回调函数。所以根据结果可以知道then
方法就是在根据promise
的状态执行对应的方法暂时基本功能都有了,进行一下测试:
和原生执行一样,成功!但是,忽略了一些细节,比如:
因为我们在
then
方法中实现是直接执行传入的函数,当这个参数不是函数因为没有做处理,把不是函数的参数当做函数执行自然就会报错,所以在then
函数中给参数加个处理修改后再次执行之前的代码,发现就没有报错了
4、实现异步
到目前为止,代码里可以看到没有任何的特殊的东西,也就是说代码会正常按顺序同步执行。但是实际上不可能是都按照顺序同步执行的。众所周知
JavaScript
有个事件循环机制,将事件分为了同步任务
和异步任务
两大类,接下来就要对异步任务
进行处理,为什么呢?举个例子:在MDN有说明,
promise
的操作会被视为异步执行,所有的promise
都是异步的,并且和setTimeout(action, 10)
特别相似。那么我们就用``setTimeout`来模拟异步。重新执行一下之前的代码,发现输出顺序就已经正确输出1,2,3,4了
5、处理收集回调
根据上一步骤可以知道
promise
和它的操作都是异步的。那么有怎么一种情况,我在promise
里也写异步事件会怎么样呢。如果了解了事件循环
的话应该会知道,这里暂且提一嘴用
事件循环
解释一下上面代码执行的过程:console.log(1);
,输出"1"new Promise()
立即执行,执行同步任务console.log(2);
并输出"2",遇见异步任务setTimeout
加入到宏任务队列(异步任务分为宏任务和微任务,promise的回调
为微任务)p.then()
,将其回调加入到微任务队列console.log(3);
并输出"3"then
回调,此时promise
状态为pending
不执行console.log(4);
并输出"4"console.log(4);
并输出"4"resolve(5);
,此时promise
状态改变,执行对应的回调,输出"5"所以输出为:
1,2,3,4,5
去_promise`上去,查看执行结果:
发现执行结果少输出一个5,而5是执行
then
的回调打印的,那么可以猜测是then
没有被执行。而我们的then
中执行是进行了状态判断的,也就是说只有当promise
状态为FULLFILLED
或者REJECTED
时才会执行。打印一下执行时的status
看看是不是它的问题继续用
事件循环
来梳理下执行过程:console.log(1)
,输出"1"new Promise()
立即执行,执行同步任务console.log(2);
,输出"2"setTimeout
加入到宏任务队列then回调
,加入到微任务队列console.log(3);
,并输出"3"then
回调,此时promise
状态为pending
没有执行结果console.log(4);
并输出"4"console.log(p.status);
,输出"pending"resolve(5);
,promise
状态改变为fullfilled
console.log(p.status);
,输出"fullfilled"观察执行过程可以发现,当
promise
的状态为pending
时,自己实现的then
方法中是没有做对应处理的。可能这就是导致了没有执行的问题。那么当状态为pending
时我们应该做什么呢?这里继续以执行顺序来理解。
then
函数是同步执行的,而获得结果是需要调用resolve
或者reject
的。那么我们怎么样才能保证then方法在获取到结果后才执行呢?解决办法就是
收集回调`。在
promise
的状态为pending
时,我们先将回调收集起来,等到执行resolve
或者reject
时,将对应的回调取出来一并执行。1、创建数组收集回调,毕竟回调可能有多个
2、在then方法中收集回调
3、resolve和reject方法中执行回调
在执行
resolve()
或者reject()
时,会遍历保存的对应的回调数组(在执行then
时保存的),并将参数传入执行。整体代码如下:
再次执行之前测试的代码,发现
then
函数的回调触发了。但是细心点还是可以发现,在打印promise
状态之后同步执行了resolve
并触发了回调,这明显是不对的,我们期望的是resolve
和reject
是异步执行的。所以这里使用setTimeout
来模拟异步再次测试输出结果,就会发现输出和原生一致了
4、测试多次执行then方法
原生
promise
可以多次调用then
,同样的也给自己实现的进行一下测试没有问题,基本大功告成!剩下最后的
promise链式调用
6、实现链式调用
首先用一个简单示例解释一下什么是链式调用
链式调用的核心就是上面的
return this
。当我们调用p.setName()
时会返回自身实例,而实例上存在setName
和sayHello
两个方法,所以就能一直.setName()
或者.sayHello()
调用下去。回到我们的
then
方法会发现在之前已经提前返回了一个new _Promise()
。因为Promise
要求then
返回一个promise
。所以这就是then
方法能够链式调用的原因。还不明白可以认真立即上面这段话。在原生
Promise
中我们是这样使用链式调用的:将同样的代码运用到自己实现的
_Promise
上后会发现有问题,因为我们then
方法还没有完善,返回的_Promise
里什么都没有。那么接下来就完善这个then
方法。1、首先将内容移动到返回的Promise中去
2、封装处理Promise返回内容的函数
3、修改then方法中的逻辑
接下来进行测试:(随便找的一个例子)
至此,已经根据原生实现了一个自己的
Promise
完整代码:
The text was updated successfully, but these errors were encountered: