一、处于then链中Promise对象的状态跟其前一个Promise对象的状态没有直接关系
即:var promise2 = promise1.then(onFulfilled, onRejected)
表达式中promise2
的状态跟promise1
没有直接关系。
// 创建promise1对象
var promise1 = new Promise((resolve, reject) => {
reject('Rejected')
})
// 创建promise2对象,来自`promise1.then`的返回值
var promise2 = promise1.then(value => {
console.log(`[promise1]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise1]: rejected, reason='${reason}'`)
})
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise1]: rejected, reason='Rejected'
[promise2]: fulfilled, value='undefined'
promise1变成了rejected
,但是 promise2却是fulfilled
状态。
1.2 分析promise2 = promise1.then(onFulfilled, onRejected)
记住两点:
-
promise1
的终态只是决定调用onFulfilled
还是onFulfilled
回调函数。 -
promise2
的终态只是受onFulfilled
ORonRejected
回调函数影响:
- 有无
onFulfilled
/onRejected
回调函数; -
onFulfilled
/onRejected
回调函数执行中是否发生异常; -
onFulfilled
/onRejected
回调函数的返回值x
。
1. 如果没有onFulfilled
/onRejected
回调函数:
如promise1是fulfilled
(rejected
)且没有onFulfilled
(onRejected
)回调函数,,此时promise2采用promise1的状态(即promise2
的状态跟promise1
的状态一致):
var promise1 = new Promise((resolve, reject) => {
reject('Rejected')
})
// promise1没有注册`onRejected`回调函数
var promise2 = promise1.then()
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise2]: rejected, reason='Rejected'
var promise1 = new Promise((resolve, reject) => {
resolve('Fulfilled')
})
// promise1没有注册`onFulfilled`回调函数
var promise2 = promise1.then()
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise2]: fulfilled, value='Fulfilled'
2. 如果 onFulfilled
/onRejected
执行过程中抛出了异常:
此时Reject
promise2对象,并且把异常作为reason。
var promise1 = new Promise((resolve, reject) => {
resolve('Fulfilled')
})
// promise1的`onFulfilled`回调函数抛出了异常
var promise2 = promise1.then(() => {
throw new Error('A Error in onFulfilled func')
})
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise2]: rejected, reason='Error: A Error in onFulfilled func'
3. 如果onFulfilled
/onRejected
函数的返回值是x
:
如果onFulfilled
/onRejected
函数正常执行完,且返回值是x
(如果没有显示指定返回值,则x为undefined
)。
3.1 如果x
也是个Promise对象,则promise2
采用x
的状态:
var promise1 = new Promise((resolve, reject) => {
resolve('Fulfilled')
})
// promise1的`onFulfilled`回调函数返回`promise1`对象
var promise2 = promise1.then(() => {
return promise1;
})
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise2]: fulfilled, value='Fulfilled
此时promise2
和promise1
具有相同的状态和相同的value。
3.2 如果x
和promise2
相等,则抛出TypeError
异常:
上个规则成立的前提就是x
和promise2
不能相等,否则就会产生互相依赖的矛盾。
如果x
和promise2
相等,则抛出TypeError
异常,并且作为promise2
对象rejected状态的reason。
var promise1 = new Promise((resolve, reject) => {
resolve('Fulfilled')
})
// promise1的`onFulfilled`回调函数返回了`promise2`
var promise2 = promise1.then(() => {
return promise2;
})
promise2.then(value => {
console.log(`[promise2]: fulfilled, value='${value}'`)
}, reason => {
console.log(`[promise2]: rejected, reason='${reason}'`)
})
输出:
[promise2]: rejected, reason='TypeError: Chaining cycle detected for promise #<Promise>'
3.3 如果x
是个thenable对象:
则执行大致下面的流程:
var then = x.then;
then.call(x, resolve, reject);
这个过程也称为PromiseResolveThenableJob
- 如果
x.then
内部先调用了resolve(y)
,则进行[[Resolve]](promise, y)
;
此时会开启新的Promise解析过程,y
千万不能和x
相等,否则会产生无限递归。 - 如果
x.then
内部先调用了rejected(y)
, 则promise2
也变成rejected
,并且把y作为reason; - 如果
x.then
内部先抛了异常, 则promise2
也变成rejected
,并且把异常作为reason;
别以为thenable对象不常见,其实Promise构造函数的实参函数就是遵循thenable对象的then方法规则。
var thenableA = {
name: 'thenableA',
then: function (resolve, reject) {
console.log(`I'am ${this.name}`);
resolve(this.name)
}
}
new Promise((resolve, reject) => {
console.log('create promise1');
resolve(thenableA)
}).then(() => {
console.log('promise1 fulfilled');
})
// promise1的`onFulfilled`回调函数返回thenableA
new Promise(resolve => {
console.log('create promise2');
resolve();
}).then(() => {
console.log('promise2 fulfilled');
})
输出:
create promise1
create promise2
I'am thenableA
promise2 fulfilled
promise1 fulfilled
注意:promise2 fulfilled
要先于promise1 fulfilled
,这是因为PromiseResolveThenableJob过程需要作为一个 job 加入微任务队列,以保证对 then 方法的解析发生在其他上下文代码的解析之后。
3.4 其他情况(即x
不是Promise对象,也不是thenable
对象):
则promise2
变成fulfilled,并且把x
作为其value。
- 如同开头的DEMO中,即使
promise1
变成了rejected
,但是promise2
却是fulfilled
状态。
因为promise1
的onRejected
回调函数的返回值x
是undefined
所以promise2
的value是undefined
。
- 如果要透传
x
,则必须显示地onFulfilled
函数里显示的返回x
。
二、promsie.finally(onFinally)
不等价于 promsie.then(onFinally, onFinally)
无论Promise处于什么终态都会触发onFinally
回调函数,但是promsie.finally(onFinally)
不等价于 promsie.then(onFinally, onFinally)
。
// Resolve
var promise2 = Promise.resolve(2)
.then(() => {});
promise2.then( value => {
console.log(`Fulfilled, value=${value}`) // value是undefined
})
var promise2 = Promise.resolve(2)
.finally( () => {});
promise2.then( value => {
console.log(`Fulfilled, value=${value}`) // value是2
})
// Reject
var promise2 = Promise.reject(2)
.then(() => {}, () => {})
// promise2 依旧是fulfilled
promise2 .then(value => {
console.log(`Fulfilled, value=${value}`) // // value是undefined
}, reason => {
console.log(`Rejected, reason=${reason}`)
})
var promise2 = Promise.reject(2).finally(() => {}, () => {});
// promise2也变成rejected
promise2 .then(value => {
console.log(`Fulfilled, value=${value}`)
}, reason => {
console.log(`Rejected, reason=${reason}`) // reason是2
})
-
onFinally
回调函数没有参数,因为它不知道Promise的终态是fulfilled还是rejected; -
finally
方法的原则是不改变then
链的执行过程(除非finally方法内部抛出异常),所以看到上面的例子中finally
方法就像不存在前后then链里一样。Promise.reject('failed') .finally(() => { console.log('handle in finally') return 'Hi i am finally'; // 显示的返回个value,但是返回的Promise对象依旧是rejected }) .then(value => { console.log(`Fullfilled: handle in then value=${value}`) }, reason => { console.log(`Rejected: handle in then reason=${reason}`) // })
-
如果
finally
的回调函数返回的是个Promise,则也是等这个Promise对象进入终态后才执行后面的then
链。Promise.reject('failed') .finally(() => { console.log('handle in finally') console.log('waiting 3s ...') return new Promise(resolve => { // 3s后再执行后面的 setTimeout(resolve, 3000) // 虽然fullfilled,但是finally方法返回的Promise对象依旧rejected }) }) .then(value => { console.log(`Fullfilled: handle in then value=${value}`) }, reason => { console.log(`Rejected: handle in then reason=${reason}`) })
-
如果
finally
的回调函数抛出异常,或则返回个rejected
的Promise,则会替换前面Promise的终态value或则reasonPromise.reject('failed') .finally(() => { console.log('handle in finally') console.log('waiting 3s ...') return new Promise((resolve, reject) => { setTimeout(() => { reject('reason from finally callback ') }, 3000) }) }) .then(value => { console.log(`Fullfilled: handle in then value=${value}`) }, reason => { console.log(`Rejected: handle in then reason=${reason}`) })
输出:
handle in finally
waiting 3s ...
Rejected: handle in then reason=reason from finally callback -
finally
的行为好奇葩,最后还是把它写在then
链的最后,以防阅读代码障碍。 -
finally
方法遵循的原则就是透传上一个Promise对象的结果,但是如果发生错误,则告诉后面的then
链最新的错误。
2.2 实现Promise.prototype.finally(onFinally)
Promise.prototype.finally = function(onFinally) {
return this.then(value => {
return Promise.resolve(onFinally())
.then(
() => value, // 透传上个Promise对象的终态`value`
reason => {
throw reason // 如果拒绝,则使用新的`reason`
});
}, reason => {
return Promise.resolve(onFinally())
.then(
() => {
throw reason // 透传上个Promise对象的终态`reason`
},
reason => {
throw reason // 如果拒绝,则使用新的`reason`
});
})
}
因为onRejected
回调都是透传新的reason
, 故省去onRejected
回调函数,即可以简化写法:
Promise.prototype.finally = function(onFinally) {
return this.then(value => {
return Promise.resolve(onFinally())
.then(() => value) // 透传上个Promise对象的终态`value`;
}, reason => {
return Promise.resolve(onFinally())
.then(
() => {
throw reason // 透传上个Promise对象的终态`reason`
});
})
}
三、Promise.resolve(value)
不等价new Promise(resolve => resolve(value))
new Promise(resolve => {
resolve();
})
.then(() => {
console.log(1)
})
Promise.resolve()
.then(() => {
console.log(2)
})
输出结果:1 -> 2,把value
改成个Promise对象试试:
var p = new Promise(resolve => {
resolve();
});
new Promise(resolve => {
resolve(p);
})
.then(() => {
console.log(1) // 回调函数会被延迟一个EventLoop
})
Promise.resolve(p)
.then(() => {
console.log(2)
})
输出结果居然变了。
-
Promise.resolve(value)中,如果实参
value
是个Promise对象(不包含thenable对象),则直接返回实参。 -
new Promise(resolve => resolve(value))
中如果value
是个Promise或则thenable对象时,则会产生PromiseResolveThenableJob,从而导致增加一个异步job。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。