promise
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。
Promise
也有一些缺点。
首先,无法取消Promise
,一旦新建它就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。
第三,当处于pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } });
resolve
函数的作用是,将Promise
对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject
函数的作用是,将Promise
对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise.then(function(value) { // success }, function(error) { // failure });
then
方法可以接受两个回调函数作为参数。
第一个回调函数是Promise
对象的状态变为resolved
时调用,
第二个回调函数是Promise
对象的状态变为rejected
时调用。
其中,第二个函数是可选的,不一定要提供。
const p1 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('fail')), 3000) }) const p2 = new Promise(function (resolve, reject) { setTimeout(() => resolve(p1), 1000) }) p2 .then(result => console.log(result)) .catch(error => console.log(error)) // Error: fail
上面代码中,p1
是一个 Promise,3 秒之后变为rejected
。
p2
的状态在 1 秒之后改变,resolve
方法返回的是p1
。
由于p2
返回的是另一个 Promise,导致p2
自己的状态无效了,由p1
的状态决定p2
的状态。
所以,后面的then
语句都变成针对后者(p1
)。
又过了 2 秒,p1
变为rejected
,导致触发catch
方法指定的回调函数
Promise.resolve() .then(() => { return new Error('error!!!') }) .then((res) => { console.log('then: ', res) }) .catch((err) => { console.log('catch: ', err) })
.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获,需要改成其中一种:
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
因为返回任意一个非 promise 的值都会被包裹成 promise 对象,
即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。
运行结果:then: Error: error!!!
at <anonymous>
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。
运行结果:1
参考:https://juejin.cn/post/6879692911680684040#heading-0
Promise.resolve() .then(function success (res) { throw new Error('error') }, function fail1 (e) { console.error('fail1: ', e) }) .catch(function fail2 (e) { console.error('fail2: ', e) })
.then 可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。
.catch 是 .then 第二个参数的简便写法,但是它们用法上有一点需要注意:
.then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch 可以捕获之前的错误。
运行结果:fail2: Error: error
at success (<anonymous>)