什么是promise
promise是es6的一个重要特性,用于实现异步。promise对象拥有一个叫做状态的属性,该属性不受外界影响,修改后不能再次变化。而Promise是一个构造函数,可以生成promise对象。
常见用法是
|
|
输出顺序是1,2,3
,为什么呢?
new Promise接受的参数函数是同步执行的,因此会马上输出1,而then中的方法是被放到mircotask队列中,在当前的代码执行完后在执行。因此先输出2,再输出3
现在让我们来打印一下Promise,看看他还有什么别的功能
构造函数的四个方法
从图片中我们可以发现Promise构造函数上带有resolve,race,all,reject四个方法,他们的共同点是都会返回一个promise。让我们来分别了解下。
resolve
先来了解下resolve
resolve接受一个值或是promise对象,如果接受的是promise对象,会直接返回该promise对象,否则返回完成状态的promise对象。
|
|
reject
类似resolve,返回的是拒绝状态的promise
all
Promise.all接受一个数组,分为三种情况
- 传入空数组,返回完成状态的promise
- 传入的数组中没有promise,返回异步完成的prmise
- 传入的数组中有promise,返回处于pending状态的promise对象,在数组中的promise都成功或者有一个失败时,变成完成状态或拒绝状态
试验一下
|
|
race
同all有点接近,在某个promise完成后,返回该值,根据状态来决定返回的是完成状态还是拒绝状态的promise
如果传入的是空数组,返回的promise永远是等待
|
|
promise对象的方法
promise带有then和catch两个方法
then
then接受两个参数,返回一个promise。
第一个参数是promise在成功的情况下的回调函数,第二个参数是失败情况下的(可选)
- 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
- 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
- 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
- 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
- 如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
catch
跟Promise.prototype.then(undefined, onRejected)
一致
promise对象的属性
打印一下a,可以看到,一个代表当前状态,一个代表值,都是不能修改的。
|
|
而将res(3)这行代码注释掉的话,a变成
|
|
而在下面的代码中,
|
|
得到的a
|
|
promise与任务队列
先看一个案例
|
|
输出结果是0,1,2,3,4
,解释一下过程。
JS执行分为mircotask和marcotask两个任务队列,其中promise属于mircotask,而js主线程代码和setTimeout属于marcotask。
这段代码的运行流程是这样的:
- 运行代码(marcotask)
- 碰到第一个console,运行,输出0
- 碰到promise构造函数,运行构造函数的参数中的函数
- 先是输出1
- 接着是碰到setTimeout,将其存放在marcotask队列
- 接着是调用res函数,将promise的状态设置为fulfilled,返回promise对象给a
- 调用a的then方法,then中的参数的函数被放在了mircotask中
- 输出最后的2,至此,当前的marcotask执行完成。
- 执行mircotask中的函数,输出3
- 执行marcotask中的函数,输出4
我们可以修改一下函数来加深下印象
|
|
可以发现,最后是输出了5个3,他的执行过程跟刚刚的很接近,区别在于倒数第二步,在调用mircotask队列中的loop函数时,又加入新的mircotask,而只有mircotask中的任务都完成后,才能执行marcotask中的函数。
promise的优缺点
优点
- 跟callback相比,避免的回调地域无限嵌套,可以使用链式写法
- 约束了异步处理的写法
- 便于捕捉错误
缺点
- 无法取消promise
- 无法处理多次触发的事件
- 无法获取当前执行的进度信息
注意,一些情况下可以使用Promise.race来取消promise。比如设置异步请求在三秒不成功的话取消,可以在Promise.race的第二个参数加一个三秒的定时器。
手写promise
|
|