Promise源码分析
前言
then/promise项目是基于promises/a+标准实现的promise库,从这个项目当中,我们来看promise的原理是什么,它是如何做到的,从而更加熟悉promise
分析
从index.js当中知道,它是先引出了./core.js,随后各自执行了其他文件的代码,通过requeire的方法。
我们首先先想一下最基础的promise用法
new promise((resolve, reject) => { resolve(4); }).then(res => { console.log(res); // export 4 });
promise中的标准
标准中规定:
promise对象初始状态为 pending,在被 resolve 或 reject 时,状态变为 fulfilled 或 rejected resolve接收成功的数据,reject接收失败或错误的数据 promise对象必须有一个 then 方法,且只接受两个可函数参数 onfulfilled、onrejectedindex.js
'use strict'; module.exports = require('./core.js'); require('./done.js'); require('./finally.js'); require('./es6-extensions.js'); require('./node-extensions.js'); require('./synchronous.js');
我们先看src/core.js
function promise(fn) { // 判断 this一定得是object不然就会报错,这个方法一定得要new出来 if (typeof this !== 'object') { throw new typeerror('promises must be constructed via new'); } // 判断fn 一定得是一个函数 if (typeof fn !== 'function') { throw new typeerror('promise constructor\'s argument is not a function'); } this._deferredstate = 0; this._state = 0; this._value = null; this._deferreds = null; if (fn === noop) return; // 最终doresolve很关键 doresolve(fn, this); }
promise是一个构造方法,开始时,它进行了校验,确保了fn是一个函数,随后对一些变量进行了初始化,最后执行了doresolve()
我们接着看doresolve这个方法。
/** * take a potentially misbehaving resolver function and make sure * onfulfilled and onrejected are only called once. * * makes no guarantees about asynchrony. */ // // 确保`onfulfilled`和`onrejected`方法只调用一次 // 不保证异步 function doresolve(fn, promise) { var done = false; var res = trycalltwo(fn, function (value) { // 如果done 为true 则return if (done) return; done = true; // 回调执行 resolve() resolve(promise, value); }, function (reason) { // 如果done 为true 则return if (done) return; done = true; reject(promise, reason); }); // res为trucalltwo()的返回值 // 如果done没有完成 并且 res 是 `is_error`的情况下 // 也会执行reject(),同时让done完成 if (!done && res === is_error) { done = true; reject(promise, last_error); } }
doresolve最关键的是执行了trycalltwo方法,这个方法的第二,第三个参数都是回调,当执行回调后,done为true,同时各自会执行resolve()或者reject()方法。最后当trycalltwo的返回值为is_error时,也会执行reject()方法。
我们先来看一下trycalltwo方法
function trycalltwo(fn, a, b) { try { fn(a, b); } catch (ex) { last_error = ex; return is_error; } }
fn实际就是promise初始化时的匿名函数(resolve, reject) => {},a,b则代表的是resolve()和reject()方法,当我们正常执行完promise函数时,则执行的是resolve则在doresolve中,我们当时执行的第二个参数被回调,如果报错,reject()被执行,则第二个参数被回调。最后捕获了异常,当发生了报错时,会return is_error,非报错时会return undinfed
再回到刚才的doresolve方法,当执行了第二个参数的回调之后,会执行resolve方法
function resolve(self, newvalue) { // promise resolution procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure // 不能吃传递自己 if (newvalue === self) { // 报错 return reject( self, new typeerror('a promise cannot be resolved with itself.') ); } // promise作为参数 if ( newvalue && (typeof newvalue === 'object' || typeof newvalue === 'function') ) { // 获取它的promise方法 读取newvalue.then var then = getthen(newvalue); if (then === is_error) { // 如果then is_error return reject(self, last_error); } if ( // 如果then是self的then // 并且promise then === self.then && // newvalue 属于promise newvalue instanceof promise ) { // _state为3 // 一般then之后走这里 // 执行then(newvalue)返回了promise self._state = 3; // selft.value为newvalue self._value = newvalue; // 当state为3时执行 finale finale(self); return; } else if (typeof then === 'function') { doresolve(then.bind(newvalue), self); return; } } self._state = 1; self._value = newvalue; finale(self); }
在没有链式调用then的情况下(也就是只要一个then)的情况下,会将内部状态_state设置成3,将传入值赋给内部变量_value最后会执行final()方法,不然则会使用doresolve来调用then
我们再来看下reject
function reject(self, newvalue) { // _state = 2为reject self._state = 2; self._value = newvalue; if (promise._onreject) { promise._onreject(self, newvalue); } finale(self); }
在reject当中我们的_state变更为了2,同样最后finale被调用。
我们来看下finale函数
// 执行自己的deferreds function finale(self) { if (self._deferredstate === 1) { handle(self, self._deferreds); self._deferreds = null; } if (self._deferredstate === 2) { for (var i = 0; i < self._deferreds.length; i++) { // 遍历handle handle(self, self._deferreds[i]); } // 将deferred 置空 self._deferreds = null; } }
在该方法当中根据不同的_deferredstate,会执行不同的handle方法。
我们再来看handle方法
function handle(self, deferred) { while (self._state === 3) { self = self._value; } // 如果有onhandle方法 则执行该方法 if (promise._onhandle) { promise._onhandle(self); } // (初始 _state 为0) if (self._state === 0) { // (初始 _deferredstate 为0) if (self._deferredstate === 0) { self._deferredstate = 1; self._deferreds = deferred; return; } // 如果 _deferredstate是1 则__deferreds是一个数组 if (self._deferredstate === 1) { self._deferredstate = 2; self._deferreds = [self._deferreds, deferred]; return; } // 当走到这里 _deferredstate应该是2 将deferred // 插入到数组当中 self._deferreds.push(deferred); return; } handleresolved(self, deferred); }
这里比较关键的应该就是通过deferredstate不同的状态,将deferred放入deferreds当中。另外当我们的_state不为0时,最终会执行handleresolved。
继续看handleresolve()方法
function handleresolved(self, deferred) { asap(function() { // _state为1时,cb = onfulfilled 否则 cb = onrejected 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; } var ret = trycallone(cb, self._value); if (ret === is_error) { reject(deferred.promise, last_error); } else { resolve(deferred.promise, ret); } }); }.then((res) => { }).catch((error) => { })
在这个方法当中,会根据我们任务(_state)的不同状态,来执行onfulfilled或者onrejected方法。当此方法调用时,也就是我们一个简单的promise的结束。
回到刚才说的promise构造方法结束的时候
设置了promise函数的一些变量
promise._onhandle = null; promise._onreject = null; promise._noop = noop;
随后在promise的原型上设置了then方法。
promise.prototype.then = function(onfulfilled, onrejected) { // 首先看这是谁构造的 如果不是promise // 则return 执行safethen if (this.constructor !== promise) { return safethen(this, onfulfilled, onrejected); } // 如果是则初始化一个promise 但是参数 noop 为空对象 {} var res = new promise(noop); // 随后执行handle方法 handle(this, new handler(onfulfilled, onrejected, res)); return res; };
在then这个方法中首先判断了它是否由promise构造的,如果不是,则返回并执行safethen,不然则执行promise构造一个res对象,然后执行handle方法,最后将promise变量res返回。handle方法之前有提过,在这里,当初始化时_state和_deferred的转改都为0,因此它会将defrred保存到promise当中。
先看一下上面说的safethen方法
function safethen(self, onfulfilled, onrejected) { return new self.constructor(function (resolve, reject) { var res = new promise(noop); res.then(resolve, reject); handle(self, new handler(onfulfilled, onrejected, res)); }); }
流程
需要有一个promise的构造方法,这个构造方法最终会执行它的参数(resolve, reject) => {},声明的then方法会通过handle()方法将onfulfilled和onrejected方法保存起来。当在外部调用resolve或者onrejected时,最终也会执行handle但是它,会最后根据状态来执行onfulfilled或者onrejected。从而到我们的then回调中。
promise的扩展
done
对done的扩展在src/done.js当中
'use strict'; var promise = require('./core.js'); module.exports = promise; promise.prototype.done = function (onfulfilled, onrejected) { var self = arguments.length this.then.apply(this, arguments) : this; self.then(null, function (err) { settimeout(function () { throw err; }, 0); }); };
内部执行了then()
finally
对finally的扩展在src/finally.js当中
在promise的标准当中,本身是没有finally方法的,但是在es2018的标准里有,finally的实现如下
'use strict'; var promise = require('./core.js'); module.exports = promise; promise.prototype.finally = function (callback) { return this.then(function (value) { return promise.resolve(callback()).then(function () { return value; }); }, function (err) { return promise.resolve(callback()).then(function () { throw err; }); }); };
promise的onfulfilled和onrejected 不管回调的哪个,最终都会触发callback 回调。还要注意的一点是finally的返回也是一个promise。
es6-extensions.js
在es6-extensions.js文件当中包含了es6的一些扩展。
promise.resolve
function valuepromise(value) { var p = new promise(promise._noop); // 将_state赋值为 非0 // _value进行保存 p._state = 1; p._value = value; // 这样做的目的是省略的一些前面的逻辑 return p; } promise.resolve = function (value) { if (value instanceof promise) return value; if (value === null) return null; if (value === undefined) return undefined; if (value === true) return true; if (value === false) return false; if (value === 0) return zero; if (value === '') return emptystring; // value return new promise if (typeof value === 'object' || typeof value === 'function') { try { var then = value.then; if (typeof then === 'function') { // 返回 返回了一个新的promise对象 return new promise(then.bind(value)); } } catch (ex) { // 如果报错 则返回一个就只 return new promise(function (resolve, reject) { reject(ex); }); } } return valuepromise(value); };
promise.reject
promise.reject = function (value) { return new promise(function (resolve, reject) { reject(value); }); };
promise.all
promise.all = function (arr) { // 类似深拷贝了一份给了args var args = array.prototype.slice.call(arr); return new promise(function (resolve, reject) { // 判断了all的promise数量 if (args.length === 0) return resolve([]); // remaining则是promise数组的长度 var remaining = args.length; // i为index val 为 promise function res(i, val) { if (val && (typeof val === 'object' || typeof val === 'function')) { if (val instanceof promise && val.then === promise.prototype.then) { while (val._state === 3) { val = val._value; } if (val._state === 1) return res(i, val._value); if (val._state === 2) reject(val._value); // val._state 为 0时 走这里 val.then(function (val) { res(i, val); }, reject); return; } else { var then = val.then; if (typeof then === 'function') { var p = new promise(then.bind(val)); p.then(function (val) { res(i, val); }, reject); return; } } } args[i] = val; // 当所有的promise执行完 则是remaining为0 // 则执行resolve(); if (--remaining === 0) { resolve(args); } } // 遍历所有的promise for (var i = 0; i < args.length; i++) { res(i, args[i]); } }); };
promise.all()返回的也是一个promise函数。
内部有一个remaining变量每当执行完一个promise函数后就会减一,当所有promise执行完,会执行自己的resolve。
promise.race
promise.race = function (values) { return new promise(function (resolve, reject) { values.foreach(function(value){ promise.resolve(value).then(resolve, reject); }); }); };
遍历传入的promise数组,经过promise.resolve(value)的可以看到,如果value是一个promise则户直接将这个value返回,最后数组中的promise哪个优先回调即执行。
promise.property.catch
catch在标准当中也是没有,虽然我们用的比较多
promise.prototype['catch'] = function (onrejected) { return this.then(null, onrejected); };
catch的回调实际是then(null, onrejected)的回调。
下一篇: 构建你的网站新闻自动发布系统之七