Promise 源码分析
栏目: JavaScript · 发布时间: 5年前
内容简介:从index.js当中知道,它是先引出了我们首先先想一下最基础的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
、onRejected
index.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)
的回调。
广而告之
本文发布于 薄荷前端周刊 ,欢迎Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 以太坊源码分析(36)ethdb源码分析
- [源码分析] kubelet源码分析(一)之 NewKubeletCommand
- libmodbus源码分析(3)从机(服务端)功能源码分析
- [源码分析] nfs-client-provisioner源码分析
- [源码分析] kubelet源码分析(三)之 Pod的创建
- Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript Web应用开发
[阿根廷] Nicolas Bevacqua / 安道 / 人民邮电出版社 / 2015-9 / 59.00元
本书是面向一线开发人员的一本实用教程,对最新的Web开发技术与程序进行了全面的梳理和总结,为JavaScript开发人员提供了改进Web开发质量和开发流程的最新技术。本书主要分两大块,首先是以构建为目标实现JavaScript驱动开发,其次介绍如何管理应用设计过程中的复杂度,包括模块化、MVC、异步代码流、测试以及API设计原则。一起来看看 《JavaScript Web应用开发》 这本书的介绍吧!