从Promise类开始
- 创建一个Promise需要传递一个函数参数,函数参数是同步执行的,函数参数可以接收到两个函数作为函数参数的参数。调用两个函数中的一个就会确定其真正状态,初始默认为pending状态,状态一旦改变就不可变。
function noop() {}
const PENDING = void 0;
const FULFILLED = 1;
const REJECTED = 2;
class Promise {
constructor(resolver) {
this._result = this._state = PENDING
this._subs = []
if (noop !== resolver) {
typeof resolver !== 'function' && needResolver()
this instanceof Promise ? initializePromise(this, resolver) : needNew()
}
}
catch(onRejection) {
return this.then(null, onRejection)
}
finally(cb) {
let promise = this
let constructor = promise.constructor
if (typeof cb === 'function') {
return promise.then(value => constructor.resolve(cb()).then(() => value),
reason => constructor.resolve(cb()).then(() => { throw reason }))
}
return promise.then(cb, cb)
}
}
function initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
resolve(promise, value);
}, function rejectPromise(reason) {
reject(promise, reason);
});
} catch(e) {
reject(promise, e);
}
}
- 如果校验都通过了,那么执行resolver并传递两个函数,如果执行报错则用reject。
- finally做一些收尾工作,无论当前promsise的状态是什么都会执行,并将promise的值传递给下一个then方法,由于then方法执行函数,其返回值会覆盖前promise的值,为了传递promise的值需要再次使用then方法传递。
不同状态下执行的方法
resolve
function resolve(promise, value) {
if (promise === value) {
reject(promise, selfFulfillment());
} else if (objectOrFunction(value)) {
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);
}
}
}
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 fulfill(promise, value) {
if (promise._state !== PENDING) { return; }
promise._result = value;
promise._state = FULFILLED;
if (promise._subscribers.length !== 0) {
asap(publish, promise);
}
}
- 执行用户传入的函数,并传入两个函数作为参数,两个函数执行后分别调用resolve和reject。
- resolve主要是处理传入的value是否有then方法,fulfill方法才是去改变promise状态。如果value存在then方法,then返回值状态落定,则修改promise状态为fulfill(无论then是reject还是fulfill),如果then返回值待定,则需要为then返回值添加回调,等待落定后调用回调。
reject
function reject(promise, reason) {
if (promise._state !== PENDING) { return; }
promise._state = REJECTED;
promise._result = reason;
asap(publishRejection, promise);
}
- reject没有对then进行解构拿到其value。
状态未定使用订阅函数
function subscribe(parent, child, onFulfillment, onRejection) {
let { _subs } = parent;
let { length } = _subscribers;
parent._onerror = null;
_subs[length] = child;
_subs[length + FULFILLED] = onFulfillment;
_subs[length + REJECTED] = onRejection;
if (length === 0 && parent._state) {
asap(publish, parent);
}
}
function publish(promise) {
let subs = promise._subs;
let settled = promise._state;
if (subscribers.length === 0) { return; }
let child, callback, detail = promise._result;
for (let i = 0; i < subs.length; i += 3) {
child = subs[i];
callback = subs[i + settled];
if (child) {
invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subs.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) {
} 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);
}
}
接下来看看then
Promise.prototype.then = then
function then(onFulfillment, onRejection) {
const parent = this
const child = new this.constructor(noop)
const { _state } = parent
if (_state) {
const cb = arguments[_state - 1]
asap(() => invokeCallback(_state, child, callback, parent._result))
} else {
subscribe(parent, child, onFulfillment, onRejection)
}
return child
}
- 如果状态已经确定就直接开启一个微/宏任务执行,否则加入promise的数组中
assp中的异步队列
const queue = [];
let len = 0;
let scheduleFlush;
function flush() {
for (let i = 0; i < len; i+=2) {
let callback = queue[i];
let arg = queue[i+1];
callback(arg);
queue[i] = undefined;
queue[i+1] = undefined;
}
len = 0;
}
if (isNode) {
scheduleFlush = () => process.nextTick(flush);
} else if (BrowserMutationObserver) {
scheduleFlush = (function() {
let iterations = 0;
const observer = new BrowserMutationObserver(flush);
const node = document.createTextNode('');
observer.observe(node, { characterData: true });
return () => {
node.data = (iterations = ++iterations % 2);
};
})();
} else if (isWorker) {
scheduleFlush = (
function useMessageChannel() {
const channel = new MessageChannel();
channel.port1.onmessage = flush;
return () => channel.port2.postMessage(0);
}
)();
} else {
scheduleFlush = (
useSetTimeout() {
const globalSetTimeout = setTimeout;
return () => globalSetTimeout(flush, 0);
}
)();
}
function asap(callback, arg) {
queue[len] = callback;
queue[len + 1] = arg;
len += 2;
if (len === 2) {
scheduleFlush();
}
}
- 同步任务优先于微任务和宏任务,即使调用了调度函数也需要等同步任务执行完才能执行flush函数,故在同步阶段仍然可以往队列中添加回调函数和promise参数。
其他几个静态方法
race
function race(entries) {
let Constructor = this;
if (!isArray(entries)) {
return new Constructor((_, reject) => reject(new TypeError('You must pass an array to race.')));
} else {
return new Constructor((resolve, reject) => {
let length = entries.length;
for (let i = 0; i < length; i++) {
Constructor.resolve(entries[i]).then(resolve, reject);
}
});
}
}
all
function all(entries) {
return new Promise((resolve, reject) => {
let cnt = 0, len = entries.length, result = []
entries.forEach((item, idx) => {
Promise.resolve(item).then((value) => {
++cnt
result[idx] = value
if (cnt === len) resolve(result)
}, (reason) => {
++cnt
reject(reason)
})
})
})
}
allSettled
function allSettled(entries) {
return new Promise((resolve) => {
let cnt = 0, len = entries.length, result = []
entries.forEach((item, idx) => {
Promise.resolve(item).then((value) => {
++cnt
result[idx] = { status: 'fulfilled', value }
if (cnt === len) resolve(result)
}, (reason) => {
++cnt
result[idx] = { status: 'rejected', reason }
if (cnt === len) resolve(result)
})
})
})
}