Promise 源码分析
栏目: JavaScript · 发布时间: 7年前
内容简介:从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使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Rails
David Griffiths / O'Reilly Media / 2008-12-30 / USD 49.99
Figure its about time that you hop on the Ruby on Rails bandwagon? You've heard that it'll increase your productivity exponentially, and allow you to created full fledged web applications with minimal......一起来看看 《Head First Rails》 这本书的介绍吧!