前言
使用Promise中,链式的调用对于控制异步执行很重要。
链式调用
在jQuery的使用中,我们常常使用下面的代码
$('#app').show().css("color","red");
这是因为jQuery的对象在调用上述方法的时候,会return
此对象本身, 以方便后面可以继续调用此对象的方法。
jQuery.fn.css = function(prop, value) {
......
return this;
}
jQuery.fn.show = function() {
......
return this;
}
Promise的链式调用
Promise是支持链式调用的,但是它是不同于上面jQuery的链式。jQeury是调用方法返回自身,但是Promise是调用方法后返回一个新的Promise。
const promise = new Promise((resolve, reject) => {
resolve('ok');
})
const promise$1 = promise.then(() => {console.log()});
promise$1 === promise // false
可以看到上面的promise$1是不等于promise的,如果可以在node.js 或者在浏览器中进行断点调试的话,还能看到promise$1的初始化状态是pending的。
当Promise的实例使用then, catch, finally添加完回调方法
以后,会返回一个初始化状态为pending
的Promise的实例对象。此对象的状态我们在外部的程序是无法进行改变的,它的状态取决于前面所注册的回调方法
的执行情况。 当回调方法
运行正常,没有产生错误或者异常,返回的值除Promise实例与本身(返回本身将会报错),返回的Promise的实例对象状态会变成resolved, 如果有错误或者异常,则会把状态变为rejected。当然了返回值是Promise的实例对象,那么次Promise实例对象的状态取决于返回的Promise实例对象的状态。
下图以then为例展示promise链式调用运行的流程
示例分析
1. 调用链then的执行顺序
const promise$0 = Promise.resolve('resolve_0');
const promise$1 = new Promise((resolve, reject) => {resolve('resolve_1')})
promise$0.then((val) => { console.log(val) }).then(() => { console.log('continue') });
promise$1.then((val) => { console.log(val) });
//输出结果: resolve_0 resolve_1 continue
promise$0与promise$1在使用then添加回掉函数之前,状态已经从pending变为resolved,它们添加的回掉函数会被立即添加到Promise的运行队列,promise$0.then((val) => { console.log(val) })
返回的Promise实例需要等待所注册的回调函数成功执行完毕以后,此Promise的状态才从pending变为resolved。 Promise的运行机制请参考: Promise的运行机制
2. 值穿透
const promise = Promise.resolve('ok');
promise.then().then((val) => {console.log(val)});
// ok
由于promise通过then没有成功添加回调函数,发生了值穿透。
3. 状态传递
const promise = Promise.resolve('complete');
promise.then((val) => {
return new Promise ((resolve) => {
resolve(val)
console.log(val, 1);
})
})
.then((val) => {console.log(val, 2)})
// complete 1 complete 2
我们把Promise暂命名(Pa), 通过promise.then返回的Promise(暂命名Pb), Pb
状态需要根据Pa
then所注册回调方法的运行,其回调方法返回一个新的Promise(暂命名Pc),由于返回的是Promise。Pb
的状态变成取决于Pc
的状态, 当Pc
的状态变化为resolved以后,Pb
的状态也变化为resolved。
4. 巧妙的异常处理
var promise = Promise.resolve('ok');
promise.then(() => {
throw new Error('error');
}).then(() => {
console.log('continue');
}).then(() => {
console.log('again');
}).catch(() => {
}).then(() => {
console.log('completed')
})
// completed
在then所注册的回调方法,发生异常以后,后续的Promise调用链的状态都是rejected,导致后续的then(resolve)
不会被推入Promise的运行队列,也就不会被运行,直到这个错误被then(,reject)
或者catch
捕获。 而使用(then(,reject))
或者catch
注册回调方法又会返回一个新的Promise,此Promise的状态又只与它们所注册的回调方法的执行相关。不会受到前面的影响。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。