文章目录
*
–
+ Promise的前提概念
+ Promise参数和执行顺序
+ Promise的嵌套执行
+ Promise.prototype.then()
+ Promise.prototype.catch()
+ finally()
+ Promise.all()
+ race()
+ Promise.allSettled()
+ Promise.any()
+ Promise.resolve()
+ Promise.reject()
+ Promise.try()
Promise的前提概念
Promise是一个构造函数,用来生成Promise实例
Promise
构造函数接受一个函数作为参数,该函数有两个参数,分别是 resolve
和 reject
resolve:成功时的回调
reject:失败时的回调
Promise分别有三个状态
1、pending :进行中
2、fulfilled:已成功
3、rejected:已失败
Promise的执行
Promise
一旦新建后就会立马执行,无法中途取消, Promise
返回的只有两种状态,并且该状态产生就无法更改。也就是说 Promise
的状态只有以下两种情况:
1、从 pending
到 fulfilled
2、从 pending
到 rejected
pending
的状态一旦改变,就不会再发生变化。
Promise的结果返回
Promise
内部结果一旦返回, resolve
或 reject
其中的任何一种,即可产生回调。
1、 resolve
的回调在 then()
中获取(成功的回调)
2、 reject
的回调在 cathc()
中获取(失败,捕获错误)
let promise = new Promise(function(resolve,reject){
let i = 5;
if( i > 1){
resolve(i)
} else {
reject(error)
}
})
promise.then(el=>{
console.log(el);
})
.catch(err=>{
console.log(err);
})
Promise的执行顺序
Promise
创建后会立马执行, then()
是一个异步回调,将在所有的同步任务执行完后执行 then()
,也就是说: Promise
在新建的时候会立即执行, then()
或 catch()
为异步任务,当所有同步任务执行完后才会执行 then()
let pro = new Promise(function(resolve,reject){
console.log('Promise新建');
resolve()
})
pro.then(el=>{
console.log('.then回调');
})
console.log('同步任务');
上述代码的执行结果:
1、Promise新建
2、同步任务
3、then()回调
Promise参数和执行顺序
resolve
函数的参数出了可以携带正常值以外,还可以携带 Promise
实例
let pro = new Promise(function(resolve,reject){
let i = 10
if(i < 50){
resolve(i)
} else {
reject(error)
}
})
let pro2 = new Promise(function(resolve,reject){
resolve(pro)
})
pro2.then(el=>{
console.log(el);
})
.catch(err=>{
console.log(err);
})
执行顺序:
先执行 pro
,如果 pro
的状态是 pending
时, pro2
则会等待执行,当 pro
的状态变成 resolve
或 rejected
时, pro2
则会立马执行,由于 pro
决定 pro2
的状态,所以后面的 then
变成了针对 pro
Promise的嵌套执行
let p = new Promise((resolve,reject)=>{
let i = 10
if(i > 5){
resolve(i)
} else {
reject('pro错误')
}
})
let p2 = new Promise((resolve,reject)=>{
p.then(el=>{
console.log(el * 2);
if(el > 6){
resolve(el)
console.log('我是p1的.then回调');
} else {
reject('pro2错误')
}
})
})
let p3 = new Promise((resolve,reject)=>{
p2.then(el=>{
if(el > 50){
resolve(el)
} else {
reject('pro3错误')
}
})
})
多个 Promise
的执行顺序:
新建 Promise
后会立马执行,先执行 Promise
内的任务,执行完成后再执行 then()
如果 Promise
内有其它 Promise
的 then()
任务执行(这里简称 p2
),会先将 p2
的 then()
任务执行完毕,再执行自身的 then()
任务
多个 Promise
并行,会先按顺序执行 Promise
的任务,再分别按照顺序分别执行他们的 then()
任务
需要
注意
的是:上面p2
的Promse
中,正常来说,resolve
或reject
执行完后,Promise
的使命应该完成,但此处因为执行顺序的问题,并没有先执行resolve
,而是执行了console
的任务,因该写成return resolve(value)
的形式,让Promise
更正常一些,否则会出现不必要的意外。
Promise.prototype.then()
then
方法是定义在原型对象 Promise.prototype
上的,它可以为 Promise
实例添加状态改变时的回调函数。
then
有两个参数(可选):
resolved
:成功状态的回调函数
rejected
:失败状态的回调函数
then
返回的是一个新的 Promise
实例,因此可以采用链式写法, then()
后面还可以接 then()
let p = new Promise((resolve,reject)=>{
let i = 5;
if(i > 4){
resolve(i)
}
})
p.then(el=>{
console.log('then1:'+ el);
if(el > 3){
return el
}
}).then(el=>{
console.log('then2:'+ el * 2);
}).catch(err=>{
console.log(err);
}
上面代码使用 then
方法,第一个 then()
回调函数执行完后,会将返回结果传入第二个回调函数,也就是说,第二个 then()
的参数是第一个 then()
返回的结果。
catch
的捕获具有冒泡性质,也就是说,前面不论 .then
了多少次,里面发生的错误,都会被最后一个 catch
捕获到。
Promise.prototype.catch()
Promise.prototype.catch()
方法是 .then(null,rejection)
的别名,也就是说, catch
其实是用来指定发生错误时的回调函数。
let p = new Promise((resolve,reject)=>{
reject('错误信息')
})
p.then(el=>{
}).catch(err=>{
console.log(err);
})
上述代码中, p
方法返回 Promise
对象,该对象返回的是 reject
, then()
方法调用回调函数, then()
有两个参数,一个 resolved
和 rejected
,如果 Promise
返回的是 reject
,那么 .then
的状态就会变成 rejected
, rejected
会调用 catch()
方法指定的回调函数,处理该错误, catch
的参数就是 reject
抛出的错误信息。
如果then运行中抛出错误,也会被catch()捕获
let p2 = new Promise((resolve,reject)=>{
resolve(100)
})
p2.then(el=>{
throw new Error('then抛错')
}).catch(err=>{
console.log(err);
})
catch捕捉错误的方式
let promise = new Promise(function(resolve,reject){
try {
throw new Error('方式一错误')
} catch(e){
reject(e)
}
})
promise.catch(err=>{
console.log(err);
})
let promise2 = new Promise(function(resolve,reject){
reject(new Error('方式二错误'))
})
promise2.catch(err=>{
console.log(err);
})
let promise3 = new Promise((resolve,reject)=>{
reject('方式三错误')
})
promise3.catch(err=>{
console.log(err);
})
以上三种效果是一样的,前两种通过 Error
抛出异常,后一种直接抛出异常
catch
返回的也是一个 Promise
对象,后面还可以接着调用 then()
方法
如果 Promise
的状态变成 resolved
,那么再抛出错误是无效的,因为 Promise
的状态一旦发生改变,就会永久保持该状态。
执行阻塞问题
Promise
内部错误不会影响到到异步队列中的 Promise
外部代码,同步代码还是会造成阻塞
let p3 = new Promise((resolve,reject)=>{
resolve(str)
})
p3.then(el=>{console.log(el)})
setTimeout(()=>{console.log('Promise外部代码')},1000)
console.log('同步代码');
finally()
finally
有最后、终于的意思,也就是说 finally()
方法不管 Promise
最后的状态如何,都会执行
let p = new Promise((resolve,reject)=>{
resolve('东方不败')
})
p.then(el=>{
console.log(el);
})
.catch(err=>{
console.log(err);
})
.finally(()=>
console.log('finally执行')
)
上述代码中,不管
Promise
最后的状态怎么样, finally
都会执行,即使没有 then()
和 catch()
, finally
也会执行
需要注意的是,
finally
不接受任何参数,但是finally
的执行顺序跟内部是否是一个函数有关,如果finally
内部是一个函数,那么finally
会在Promise
最后执行,如果finally
内部没有任何函数,直接输出,那么finally
会在Promise
最前面执行。
finally
的执行跟 Promise
的状态无关。
Promise.all()
Promise.all()
方法用于将多个 Promise
实例包装成一个新的 Promise
实例
语法: let p = Promise.all([p1,p2,p3])
let p = new Promise((resolve,reject)=>{
resolve(10)
})
p.then(el=>{
console.log(el);
})
let p2 = new Promise((resolve,reject)=>{
reject(20)
})
p2.then(el=>{
console.log(el);
})
.catch(err=>{console.log('p2:',err);})
Promise.all([p,p2])
.then(el=>{
console.log(el);
})
.catch(err=>{console.log('all:',err);})
当 Promise.all
的两个 promise
参数状态都变成 fulfilled
时,才会触发 Promise.all()
的方法,如果其中以一个参数被 rejected
,那么 Promise.all()
也会变成 rejected
的状态,会被 catch
捕捉。
上面代码中,如果 p2
没有 chach
方法,则会调用 Promise.all()
的 catch
race()
Promise.race()
方法可以将多个 Promise
实例包装成一个新的 Promise
实例。
语法: let p = Promise.race([p1,p2,p3])
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p1状态')
},2000)
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p2状态')
},1000)
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p3状态')
},3000)
})
let p4 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('reject:p4状态')
},4000)
})
let promise = Promise.race([p,p2,p3,p4])
promise
.then(el=>{
console.log(el);
})
.catch(err=>{
console.log(err);
})
race
有竞争,角逐的意思,该方法其实就是参数中,哪一个 Promise
的状态先发生改变,就调用先发生改变的 promise
,这个 el
就是最先发生改变的 promise
的返回值。
Promise.allSettled()
Promise.allSettled()
方法可以在所有异步操作都结束的情况下,调用该方法。它与 Promise.all()
方法不同的是, all()
方法需要所有异步都成功才会进入 then()
,而 allSettled()
不需要。
let p = new Promise((resolve,reject)=>{
resolve('p1状态')
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('p2状态')
},3000)
})
Promise.allSettled([p,p2])
.then(el=> console.log(el) )
Promise.any()
Promise.any()
方法接受一组 Promise
实例作为参数,包装成一个新的 Promise
实例返回。
let p = new Promise((resolve,reject)=>{
resolve('p1状态')
})
let p2 = new Promise((resolve,reject)=>{
reject('p2状态')
})
Promise.any([p,p2])
.then(el=>{
console.log('then:',el);
})
.catch(err=>{
console.log('catch:',err);
})
只要有一个参数的状态变成 fulfilled
, Promise.any
就会变成 fulfilled
状态
如果所有的参数实例都变成 rejected
状态,包装实例才会变成 rejected
状态
也就是说, any
是只要有一个参数成功, any
就可以 then
,所有参数都 reject
, any
才会 catch
Promise.resolve()
Promise.resolve()
可以将现有对象转为 Promise
对象, Promise.resolve()
方法就起到这个作用。
语法: let p = Promise.resolve(obj)
let p = Promise.resolve('obj')
p.then(el=> console.log(el))
let p2 = new Promise(resolve=>resolve('obj'))
如果 Promise.resolve()
没有参数,那么将直接返回 resolved
状态的 Promise
对象,并且是一个没有参数的 then()
方法。
let p3 = Promise.resolve()
p3.then(el=>{
console.log(el);
})
setTimeout(()=>{
console.log('定时器');
},0)
Promise.resolve()
.then(()=>{
setTimeout(()=>{console.log('resolve内定时器')},0)
console.log('resolve内部');
})
console.log('外部');
Promise.reject()
Promise.reject()
返回一个新的 Promise
实例,该实例的状态为 rejected
let p = Promise.reject('错误信息')
p.catch(err=>console.log(err))
let p2 = new Promise((resolve,reject)=>{
reject('错误信息2')
})
p2.catch(err=>console.log(err))
Promise.try()
实际开发中,会遇到这么一种情况,不管函数是同步还是异步的,都想用 Promise
来处理它,因为这样就可以用 then()
指定下一步流程, catch
处理抛出的错误,更便于管理流程。
基于 Promise
我们可以用 async
做到同步的代码风格执行异步操作,现在有一个最新的提案,使用 Promise.try()
来捕获所有的同步和异步错误。
为什么这么做?
Promise
抛出的错误, catch
可以捕获到,但此处仅限于当前 Promise
的异常错误,也就是异步的。如果同步错误抛出,那么 catch()
是捕捉不到的,需要在外层再嵌套一层 try...catch
,这样写起来非常麻烦,代码如下:
try {
let p = new Promise((resolve,reject)=>{
reject('异步错误')
})
p.catch(err=> void console.log(err) )
throw Error('同步错误')
} catch (e) {
console.log(e);
}
如果使用 Promise.try()
就可以捕获所有的同步和异步错误
Promise.try(()=>{
let p2 = new Promise((resolve,reject)=>{
reject('异步错误2')
})
throw Error('同步错误2')
})
.then(el=>{
console.log('then:',el);
})
.catch(err=>{
console.log('catch:',err);
})
此处的 Promise.try
就相当于 try
代码块, Promise.catch
就相当于 catch
代码块。
案例源码:https://gitee.com/wang_fan_w/es6-science-institute
如果觉得这篇文章对你有帮助,欢迎点亮一下star哟
Original: https://blog.csdn.net/qq_44793507/article/details/128737628
Author: fanction
Title: 深入理解Promise
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/812707/
转载文章受原作者版权保护。转载请注明原作者出处!