Promise解密之then/promise源码分析
https://github.com/then/promise
文桥 2017/03/06
文桥 2017/03/06
function sync(){
console.log('I am a sync method!')
}
sync()
// 貌似阻塞了 3 秒,效果有点像 php 中的 sleep()
// 但原理是完全不同的,下面我们一起来看看这到底是如何实现的
var p = new Promise(function(onFulfilled, onRejected){
console.log(`${new Date()}: I am s sync method, too!`)
setTimeout(function(){
onFulfilled(`${new Date()}: I am a async method!(fulfilled)`)
}, 3000)
})
p.then(
(result) => {console.log(result)},
(error) => {console.log(error)}
)
// I am a sync method!
// Mon Feb 27 2017 01:55:51 GMT+0800 (CST): I am s sync method, too!
// Mon Feb 27 2017 01:55:54 GMT+0800 (CST): I am a async method!(fulfilled)
var p = new Promise(function(onFulfilled, onRejected){
console.log('I am s sync method, too!')
setTimeout(function(){
onFulfilled('I am a async method!(fulfilled)')
}, 3000)
})
function Promise(fn) {
// ...
this._deferredState = 0;
this._state = 0;
this._value = null;
this._deferreds = null;
if (fn === noop) return;
doResolve(fn, this);
}
function doResolve(fn, promise) {
var done = false; // 确保只执行 resolve 或 reject
var res = tryCallTwo(fn, function (value) {// onFulfilled
if (done) return;
done = true;
resolve(promise, value);
}, function (reason) {// onRejected
if (done) return;
done = true;
reject(promise, reason);
});
// ...
}
// fn 为 Promise 传入的匿名函数; 在 fn 中 return 任何值都不会影响 then
function tryCallTwo(fn, a, b) {
try {// 执行用户业务逻辑代码,若发生意外错误,直接退出
fn(a, b);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
// newValue 为 resolve 的参数
function resolve(self, newValue) {
// ...
// 各种参数的校验
self._state = 1;
self._value = newValue;
finale(self);
}
// 由于此时 _deferredState = 0 所以直接跳过 finale
// 但是我们在后面会看到 finale 的强大作用
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(self, self._deferreds[i]);
}
self._deferreds = null;
}
}
// Promise 解决过程结束
// 实例化的过程不算复杂,最终会返回给我们一个 Promise 对象
{
_deferredState: 0,
_state: 1 | 2 | 3,
_value: Promise | thenable | others,
_deferreds: null
}
// 通过对 Promise 构造过程的分析
// 我们知道在构造函数中的异步任务还是被添加到了事件循环的任务队列中
setTimeout(function(){// async1
onFulfilled('I am a async method!')
}, 3000)
var p1 = new Promise(function(onFulfilled, onRejected){
console.log('I am s sync method, too!')
setTimeout(function(){
onFulfilled('I am a async method!')
}, 3000)
})
var p2 = p1.then(
(result) => {console.log(result)},
(error) => {console.log(error)}
)
var p3 = p2.then(
() => {console.log('then-2-onFulfilled')},
() => {console.log('then-2-onRejected')}
)
var p4 = p3.then(
() => {
console.log('then-3-onFulfilled')
},
() => {console.log('then-3-onRejected')}
)
console.log(JSON.stringify(p0))
// I am a sync method!
// Mon Feb 27 2017 02:55:22 GMT+0800 (CST): I am s sync method, too!
// {"_deferredState":1,"_state":0,"_value":null,"_deferreds":{"promise":{"_deferredState":1,"_state":0,"_value":null,"_deferreds":{"promise":{"_deferredState":1,"_state":0,"_value":null,"_deferreds":{"promise":{"_deferredState":0,"_state":0,"_value":null,"_deferreds":null}}}}}}}
// Mon Feb 27 2017 02:55:25 GMT+0800 (CST): I am a async method!
// then-2-onFulfilled
// then-3-onFulfilled
{
"_deferredState": 1,
"_state": 0,
"_value": null,
"_deferreds": {
"promise": {
"_deferredState": 1,
"_state": 0,
"_value": null,
"_deferreds": {
"promise": {
"_deferredState": 1,
"_state": 0,
"_value": null,
"_deferreds": {
"promise": {
"_deferredState": 0,
"_state": 0,
"_value": null,
"_deferreds": null
}
}
}
}
}
}
}
Promise.prototype.then = function(onFulfilled, onRejected) {
// 是 thenable 但不是原生的 Promise 实例时执行(非法的 then 时执行)
if (this.constructor !== Promise) {
return safeThen(this, onFulfilled, onRejected);
}
// 这里处理的十分巧妙(链表就是在这里形成的)
var res = new Promise(noop); // 实例化一个新的 Promise
handle(this, new Handler(onFulfilled, onRejected, res));
return res;
};
// new Handler():deferred(数据结构)
// {
// onFulfilled: function | null,
// onRejected: function | null,
// promise: Promise // then 产生的新 Promise
// }
function Handler(onFulfilled, onRejected, promise){
// 后面会提到 Promise 击穿问题;这里就是产生击穿的原因
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
function handle(self, deferred) {
// ...
if (self._state === 0) {
if (self._deferredState === 0) {
self._deferredState = 1;
self._deferreds = deferred; // 链式处理
return;
}
if (self._deferredState === 1) {// 什么时候为 1 呢?
self._deferredState = 2;
self._deferreds = [self._deferreds, deferred];
return;
}
self._deferreds.push(deferred);
return;
}
handleResolved(self, deferred);
}
function handleResolved(self, deferred) {
// 每个 then() 最终都会向 任务队列里添加一个匿名函数
// 这里我们依次叫 async2、async3、saync4
setImmediate(function() {// async2
// ...
});
}
function() {// async2
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;
}
// ret 为 IS_ERROR 或者 onFulfilled/onRejected 的返回值
var ret = tryCallOne(cb, self._value);
if (ret === IS_ERROR) {
reject(deferred.promise, LAST_ERROR);
} else {
// 当你在 then 中 return 了一个新的 promise
// 便会 resolve(deferred.promise, promise)
// resolve 中会修改 _state = 3
// handle 时便会走 while 用新的 promise 替换旧的(跳过 deferred.promise)
// 于是执行的任务又基于一个新的 Promise 按我们预想的流程继续进行
resolve(deferred.promise, ret);
}
}
function tryCallOne(fn, a) {
try {
// return 很重要,意味着你可以在
// onFulfilled/onRejected 中 return 任何值,当然包括 Promise
return fn(a);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
doSomething()
.then(function () {
return doSomethingElse()
})
.then(finalHandler)
doSomething()
.then(function () {
doSomethingElse()
})
.then(finalHandler)
doSomething()
.then(doSomethingElse())
.then(finalHandler)
doSomething()
.then(doSomethingElse)
.then(finalHandler)
doSomething
|-----------------|
doSomethingElse
|------------------|
finalHandler
|------------------|
doSomething
|-----------------|
doSomethingElse
|------------------|
finalHandler
|------------------|
doSomething
|-----------------|
doSomethingElse
|---------------------------------|
finalHandler
|------------------|
doSomething
|-----------------|
doSomethingElse
|------------------|
finalHandler
|------------------|