首先看一下promise的使用:
let promise = new Promise((resolve, reject) => {
// on success
resolve(value);
// on failure
reject(reason);
});
promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
Promise内部定义
(1)三种状态:
const PENDING = void 0;
const FULFILLED = 1;
const REJECTED = 2;
(2)定义PROMISE_ID ,一个Promise实例唯一标识
const PROMISE_ID = Math.random().toString(36).substring(2);
(3)空函数:标注调用Promise是内部方法(源码里面的使用)还是外部方法
function noop() {}
(4)nextId:表示一个promise调用链的自增id
let id = 0;
function nextId() {
return id++;
}
我们按照promise的执行顺序一一分析:
第一步: 构造函数Promise
new Promise()入口,调用Promise函数时会执行这段代码。
class Promise {
constructor(resolver) { // resolver就是调用new Promise传入的回调函数
this[PROMISE_ID] = nextId();
// _result 保存 resolve 时的 value 或者 reject 时的 reason
// _state 保存 promise 的 当前状态 初始化为 Pending
this._result = this._state = undefined;
this._subscribers = []; // 订阅列表
// 若resolver为空函数,表示源码里面的promise调用,就不执行以下逻辑
if (noop !== resolver) {
// 判断resolver 如果不是一个函数,就报错You must pass a resolver function as the first argument to the promise constructor
typeof resolver !== 'function' && needsResolver();
// 判断该实例是否是Promise构造函数的实例,是的话就执行 initializePromise(this, resolver)
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
}
}
catch(onRejection) {
return this.then(null, onRejection);
}
finally(callback) {
let promise = this;
let constructor = promise.constructor;
if ( isFunction(callback) ) {
return promise.then(value => constructor.resolve(callback()).then(() => value),
reason => constructor.resolve(callback()).then(() => { throw reason; }));
}
return promise.then(callback, callback);
}
}
/**
* @resover 就是调用promise传入的回调函数,即
* (resolve, reject) => {
* resolve(value); // 执行resolvePromise函数
* reject(reason); // 执行rejectPromise
* }
*/
function initializePromise(promise, resolver) {
try {
// 调用resolver回调函数,它有两个参数resolvePromise,rejectPromise,
// 当promise状态为FULFILLED执行resolvePromise,为REJECTED执行rejectPromise
resolver(function resolvePromise(value){
resolve(promise, value);
}, function rejectPromise(reason) {
reject(promise, reason);
});
} catch(e) {
reject(promise, e);
}
}
此时promise实例如图
第二步 then函数
then函数返回一个新promise对象,判断promise状态执行不同逻辑,如果promise状态为pending,把回调函数放入_subscribers,否则就执行invokeCallback
// 1.生产新的promise实例child
// 2.根据promise状态判断,如果pending,就走subscribe函数,否则走invokeCallback()
// 3.返回child
export default function then(onFulfillment, onRejection) {
const parent = this;
const child = new this.constructor(noop); // 传入空函数,即没有resolver,内部调用Promise
// promise是空的时候处理
if (child[PROMISE_ID] === undefined) {
makePromise(child);
}
const { _state } = parent;
if (_state) {
// 调用then时promise状态不为pending时执行
const callback = arguments[_state - 1];
asap(() => invokeCallback(_state, child, callback, parent._result));
} else {
// 调用then时promise状态为pending时执行,订阅事件
subscribe(parent, child, onFulfillment, onRejection);
}
return child; // 链式调用的基础
}
// 父子实例建立联系,形成链式
/**
* @param {promise} parent 被订阅状态变化的Promise
* @param {promise} child 订阅状态变化的Promise(可为undefined)
* @param {function} onFulfillment 状态变化为 fulfilled 的订阅函数
* @param {function} onRejection 状态变化为 rejected 的订阅函数
*/
function subscribe(parent, child, onFulfillment, onRejection) {
let { _subscribers } = parent;
let { length } = _subscribers;
parent._onerror = null;
// 每3个为一组,每调用一次subscribe函数 订阅序列会增加三个元素
_subscribers[length] = child; // 第3n项是子实例
_subscribers[length + FULFILLED] = onFulfillment; // 第3n+1项是成功回调
_subscribers[length + REJECTED] = onRejection; // 第3n+2项是失败回调
if (length === 0 && parent._state) {
asap(publish, parent);
}
}
比如下面的代码执行结果
let p = new EsPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000)
})
p.then(res => {
console.log(222)
return 333;
})
.then(res => {
console.log(res)
})
返回的结果,父子实例关系如下:
then链式调用关系图如下:
p1,p2,p3代表promise实例,cb1、cb2分别代表成功回调onFulfillment、失败回调onRejection
多次调用一个实例, 订阅并列存入_subscribers列表
let p = new EsPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000)
})
p.then(res => {
console.log(222)
return 333;
})
p.then(res => {
console.log(res)
})
then拿到了成功和拒绝的函数,之后创建一个新的promise,并且将函数添加到事件队列等着setTimeout触发resolve函数。
第三步 Promise异步回调执行
let p = new EsPromise((resolve, reject) => {
setTimeout(() => {
resolve(111); // 调用resove,看这里
}, 1000)
})
当调用reslove或者reject函数时,会执行resolvePromis或rejectPromise
当异步成功时,调用resolve函数,执行一下逻辑
function initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
resolve(promise, value); // 执行这里,
}, function rejectPromise(reason) {
reject(promise, reason);
});
} catch(e) {
reject(promise, e);
}
}
// 根据promise结果值执行不同的逻辑
function resolve(promise, value) {
if (promise === value) {
// 如果resolve值是本实例,报错
reject(promise, selfFulfillment());
} else if (objectOrFunction(value)) {
// 判断 value是对象或者函数,比如 {then: (resolve, reject) => {]}, () => {},即thenable
let then;
try {
then = value.then;
} catch (error) {
reject(promise, error);
return;
}
handleMaybeThenable(promise, value, then);
} else {
// 普通数据走这里
fulfill(promise, value);
}
}
// 如果终值是对象或函数执行
function handleMaybeThenable(promise, maybeThenable, then) {
if (maybeThenable.constructor === promise.constructor &&
then === originalThen &&
maybeThenable.constructor.resolve === originalResolve) {
handleOwnThenable(promise, maybeThenable);
} else {
if (then === undefined) {
fulfill(promise, maybeThenable);
} else if (isFunction(then)) {
handleForeignThenable(promise, maybeThenable, then);
} else {
fulfill(promise, maybeThenable);
}
}
}
// 如果终值是promise实例
function handleOwnThenable(promise, thenable) {
if (thenable._state === FULFILLED) {
fulfill(promise, thenable._result);
} else if (thenable._state === REJECTED) {
reject(promise, thenable._result);
} else {
subscribe(thenable, undefined, value => resolve(promise, value),
reason => reject(promise, reason))
}
}
// 如果终值是函数
function handleForeignThenable(promise, thenable, then) {
asap(promise => {
let sealed = false;
let error = tryThen(then, thenable, value => {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
resolve(promise, value);
} else {
fulfill(promise, value);
}
}, reason => {
if (sealed) { return; }
sealed = true;
reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
reject(promise, error);
}
}, promise);
}
// 更新promise的状态为 fulfilled 同时向订阅序列发出通知
function fulfill(promise, value) {
if (promise._state !== PENDING) { return; }
promise._result = value;
promise._state = FULFILLED;
// promise的状态发生了改变
// 向订阅序列发出通知
if (promise._subscribers.length !== 0) {
asap(publish, promise); // 相当于执行publish(promise)
}
}
// 当一个promise状态更新之后,就会触发publish函数,发布修改
function publish(promise) {
let subscribers = promise._subscribers;
let settled = promise._state;
if (subscribers.length === 0) { return; }
let child, callback, detail = promise._result;
// 每三个是一个订阅通知,[promise, fulFilled, rejected]
for (let i = 0; i < subscribers.length; i += 3) {
// 子实例 有可能是undefined
child = subscribers[i];
// 根据promise状态取出回调函数, settled是已经变化的状态值,fulFilled为1,rejected为2
callback = subscribers[i + settled];
if (child) {
// 有promise实例调用
invokeCallback(settled, child, callback, detail);
} else {
// 没有子promise实例
callback(detail);
}
}
promise._subscribers.length = 0;
}
function invokeCallback(settled, promise, callback, detail) {
let hasCallback = isFunction(callback),
value, error, succeeded = true;
if (hasCallback) {
try {
value = callback(detail);
} catch (e) {
succeeded = false;
error = e;
}
if (promise === value) {
reject(promise, cannotReturnOwn());
return;
}
} else {
value = detail;
}
if (promise._state !== PENDING) {
// noop
} else if (hasCallback && succeeded) {
resolve(promise, value);
} else if (succeeded === false) {
reject(promise, error);
} else if (settled === FULFILLED) {
fulfill(promise, value);
} else if (settled === REJECTED) {
reject(promise, value);
}
}
asap flush
export var asap = function asap(callback, arg) {
queue[len] = callback;
queue[len + 1] = arg;
len += 2;
if (len === 2) {
// 当len为2的时候就会执行异步flush,之后的回调函数在加进来会自动执行
if (customSchedulerFn) {
customSchedulerFn(flush);
} else {
scheduleFlush(); // 执行flush
}
}
}
const queue = new Array(1000);
function flush() {
for (let i = 0; i < len; i+=2) {
let callback = queue[i]; // 比如publish
let arg = queue[i+1]; // promise实例
callback(arg); // publish(promise),
queue[i] = undefined;
queue[i+1] = undefined;
}
len = 0;
}
首先向queue中push一对callback和arg,此时len==2
这是flush中的遍历就能运行起来,开始遍历,从queue中取出callback和arg,开始执行callback(arg)
在执行callback的过程中,又向queue中push一个callback和一个arg,此时len变成了4
那么flush中的for循环在遍历一遍后本来是要终止的,但是callback把len变成了4,又可以继续往下遍历queue
最终的流程
- 选择异步方式,触发flush, 比如useMutationObserver
- then
- subscribe
- resolve
- fulfill
- asap
- queque
- flush
- publish
- invokeCallback -> resove 循环4-10步
异步调用flush - scheduleFlush
通过不同状态,将scheduleFlush赋值为某个函数,
const browserWindow = (typeof window !== 'undefined') ? window : undefined;
const browserGlobal = browserWindow || {};
const BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
const isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
// test for web worker but not in IE10
const isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// 是否是node环境
function useNextTick() {
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
// see https://github.com/cujojs/when/issues/410 for details
return () => process.nextTick(flush);
}
//支持require函数的环境
function useVertxTimer() {
if (typeof vertxNext !== 'undefined') {
return function() {
vertxNext(flush);
};
}
return useSetTimeout();
}
// BrowserMutationObserver判断是否是浏览器环境。
function useMutationObserver() {
let iterations = 0;
const observer = new BrowserMutationObserver(flush);
const node = document.createTextNode('');
observer.observe(node, { characterData: true });
return () => {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function useMessageChannel() {
const channel = new MessageChannel();
channel.port1.onmessage = flush;
return () => channel.port2.postMessage(0);
}
// 其他情况
function useSetTimeout() {
// Store setTimeout reference so es6-promise will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
const globalSetTimeout = setTimeout;
return () => globalSetTimeout(flush, 0);
}
let scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (isNode) {
scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
scheduleFlush = useMutationObserver();
} else if (isWorker) {
scheduleFlush = useMessageChannel();
} else if (browserWindow === undefined && typeof require === 'function') {
scheduleFlush = attemptVertx();
} else {
scheduleFlush = useSetTimeout();
}
这里所有的函数要做的都只有一个事情,就是执行flush函数。