实例方法then
then方法的作用
Promise的状态属性[[PromiseState]]不暴露在Promise对象上,所以不能以编程的方式检测Promise的状态,只有当Promise的状态改变时,通过then()方法采取特定的行动。接受两个参数:第一个是当Promise的状态变为fulfilled时要调用的函数,与异步操作相关的附加数据都会传递给这个完成函数(fulfillment function);第二个是当Promise的状态变为rejected时要调用的函数,所有与失败状态相关的附加数据都会传递给这个拒绝函数(rejection function)。
then方法的源码
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.constructor !== Promise) {
// 当前constructor不是Promise的构造器时,做些什么
return safeThen(this, onFulfilled, onRejected)
}
// 定义一个空的promise对象
var res = new Promise(noop)
// 添加成功处理函数和失败处理函数绑定
handle(this, new Handler(onFulfilled, onRejected, res))
// 将promise对象return,以便then的链式调用
return res
}
function handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
this.onRejected = typeof onRejectd === 'function' ? onRejected : null
this.promise = promise
}
function handle (self, deferred) {
.....
handleResolve(self, deferred)
}
function handleResolve(self, deferred) {
// 通过当前执行状态判断cb设置为成功函数还是拒绝函数
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected
if (cb === null) {
if (self._state === 1) { // 执行成功,但没有传入成功处理函数,再次调用resolve,以便下一个串联的then方法捕获
resolve(deferred,promise, self._value)
} else {
reject(deferred,promise, self._value)
}
return
}
// tryCallOne方法实现从resolve到then方法的值的穿透
var ret = tryCallOne(cb, self._value) {
if (ret === IS_ERROR) {
reject(deferred,promise, LAST_ERROR)
} else {
resolve(deferred,promise, ret)
}
}
}
then的源码当中实现两个功能点:第一,then的链式调用;第二,reject和resolve输出值的穿透到then中处理。
-
then的链式调用的实现,代码如下:
Promise.prototype.then = function (onFulfilled, onRejected) { .... var res = new Promise(noop) handle(this, new Handler(onFulfilled, onRejected, res)) return res }首先在then的处理方法中又重新实例化了Promise对象,并且由Promise学习笔记-二一文中的源码可以看到实例化时传入的noop是一个空函数,目的就是让
then返回一个Promise对象。因为每个Promise对象都必定有自己的then处理函数,所以就达到了链式调用的目的。 -
从实例化时传入
resolve或reject的值,到then方法的穿透,实现代码如下:function tryCallOne(fn, a) { try { return fn(a) } catch (ex) { LAST_ERROR = ex return IS_ERROR } }把
then方法中传入的成功或失败处理函数和当前self._value传入到tryCallOne()方法,内部通过fn(a)实现self._value到then的穿透。 -
链式调用时的穿透。先看一个例子
let promise = new Promise(function (resolve, reject) { resolve(2) }).then(null).then(res => { console.log(res) // 2 })第一个then方法没有传成功处理函数时,第二个
then房输出了resolve中的值。在handleResolve()方法中做了什么?function handleResolve (self, deferred) { var cb = self._state === 1 ? deferred.onFulfilled ? deferred.onRejected if (cb === null) { if (self._state === 1) { resolve(deferred.promise, self._value) } else { reject(deferred.promise, self._value) } return } }通过
handler实例我们可以知道,当第一个then传入null时,在handleResolve()方法中的cb为null,且此时当前状态值self._state又为1,所以又重新调用了resolve()方法,且return掉了。此时相当于var res = new Promise(noop)实例添加了resolve的处理方法,进而第二个then方法可以处理并得到结果2。
实例方法catch
catch()方法相当于只给其传入拒绝处理程序的then()方法。所以它的实现过程调用了实例上的then()方法。源码如下:
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected)
}
实例方法finally
finally方法的作用
finally()方法用于指定不管Promise对象状态如何,都会执行的操作。finally()的回调函数不接受任何参数,意味着没办法知道,前面的Promise的状态到底是fulfilled还是rejected。这表明finally里面的操作不依赖于Promise的执行结果。
finally用法
服务器使用Promise处理请求,然后使用finally关掉服务器
server.listen(port).then(function () {
....
}).finally(server.stop)
finally方法的源码
finally()本质上是then方法的特例。实现过程如下代码:
Promise.prototype.finally = function (f) {
return this.then(function (value) {
return Promise.resolve(f ()).then(function () {
return value
})
}, function (reason) {
return Promise.resolve(f ()).then(function () {
throw reason
})
})
}