一、 constructor实现
根据规范2.1,一个Promise有三种状态(pending,fulfilled,rejected),所以首先定义三个状态常量:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
接下来实现构造器MyPromise:
function MyPromise(executor) {
// 只能作为构造函数调用
if (new.target !== MyPromise) {
throw Error('MyPromise must be called as a constructor');
}
//executor必须为函数
if (typeof executor !== 'function') {
throw TypeError('executor must be a function');
}
//初始化状态为pending
this.state = PENDING;
this.value = null;
this.reason = null;
//存放状态变为fulfilled时需执行的回调函数
this.onFulfilledCallbacks = [];
//存放状态变为rejected时需执行的回调函数
this.onRejectedCallbacks = [];
this.resolve = (value) => {} //稍后实现
this.reject = (err) => {} // 稍后实现
try {
//构造函数执行时立即执行executor函数,接收resolve和reject两个参数
executor(this.resolve, this.reject);
}catch(e){
// 当executor执行发生错误时,调用this.reject修改MyPromise的状态,并执行状态为rejected时的回调
this.reject(e);
}
}
二、 resolve函数实现
this.resolve = (value) => {
if (value instanceof MyPromise) {
// 当value状态改变时接收终值
return void value.then(this.resolve, this.reject);
}
// 规范2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,
// 规范注解1,确保onFulfilled异步调用
setTimeout(() => {
// 规范2.1.2.1 当状态由pending变为fulfilled时,不得再改变,因此加这个判断
if (this.state === PENDING) {
this.value = value;
// 修改状态为fulfilled
this.state = FULFILLED;
//规范 2.2.6.1 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
// 执行所有onFulfilled回调
this.onFulfilledCallbacks.forEach(cb => cb());
}, 0);
}
三、reject函数实现
this.reject = (err) => {
setTimeout(() => {
// 规范2.1.2.1 当状态由pending变为fulfilled时,不得再改变,因此加这个判断
if (this.state === PENDING) {
this.reason = err;
// 修改状态为 rejected
this.state = REJECTED;
//规范 2.2.6.2 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
// 执行所有onRejected回调
this.onRejectedCallbacks.forEach(cb => cb());
}, 0);
}
四、 then方法实现
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let promise;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
if (this.state === FULFILLED) {
promise = new Promise((resolve, reject) => {
// 规范2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,
// 规范注解1,确保onFulfilled异步调用
setTimeout(() => {
try {
// 规范2.2.5 onFulfilled和onRejected必须作为函数调用
const x = onFulfilled(this.value);
//规范2.2.7.1 如果 onFulfilled 或者 onRejected 返回一个值 x ,
//则运行Promise 解决过程:[[Resolve]](promise2, x)
resolutionProcedure(promise, x); //稍后实现
}catch(e) {
//规范2.2.7.2 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
reject(e)
}
}, 0)
})
}
if (this.state === REJECTED) {
promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolutionProcedure(promise, x);
}catch(e) {
reject(e);
}
}, 0)
})
}
if (this.state = PENDING) {
promise = new MyPromise((resolve, reject) => {
// 当状态为pending时,将onFulfilled和onRejected回调收集起来
this.onFulfilledCallbacks.push(() => {
try {
const x = onFulfilled(this.value);
resolutionProcedure(promise, x);
}catch(e) {
reject(e);
}
});
this.onRejectedCallbacks.push(() => {
try {
const x = onReject(this.reason);
resolutionProcedure(promise, x);
}catch (e) {
reject(e);
}
})
})
}
// 规范2.2.7 then方法必须返回一个新的promise对象
return promise;
}
上面的函数有一些重复代码,我们可以提取出一个公共函数modifyPromise2(promise2, value, cb, reject),其中promise2为then方法要返回的新的promise,value为状态为fulfilled或rejected时对应的value/reason,cb为onFulfilled或onRejected回调函数
function modifyPromise2(promise2, value, cb, reject) {
try {
const x = cb(value);
resolutionProcedure(promise2, x);
}catch(e) {
reject(e);
}
}
因此,最终then方法为:
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let promise;
//规范 2.2.1.1 忽略不是函数的onFulfilled,使用identity函数使值能够传递给下个then调用
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
//规范 2.2.1.2 忽略不是函数的onRejected,重置为一个将传入参数作为错误抛出的函数,使错误能够
//传递给下一个then调用
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
if (this.state === FULFILLED) {
promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
modifyPromise2(promise, this.value, onFulfilled, reject);
});
});
}
if (this.state === REJECTED) {
promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
modifyPromise2(promise, this.reason, onRejected, reject);
})
})
}
if (this.state === PENDING) {
promise = new MyPromise((resolve, reject) => {
this.onFulfilledCallbacks.push(() => {
modifyPromise2(promise, this.value, onFulfilled, reject);
});
this.onRejectedCallbacks.push(() => {
modifyPromise2(promise, this.reason, onRejected, reject);
})
})
}
return promise;
}
五、 resolutionProcedure(promise, x)实现
function resolutionProcedure(promise, x) {
// 规范2.3.1 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
if (promise === x) {
throw TypeError('循环引用,会引起无穷递归');
}
if (x instanceof MyPromise) {
//规范2.3.2 如果x为MyPromise, 获取它的状态
const state = x.state;
if (state === PENDING) {
//规范2.3.2.1 如果为pending,如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
x.then(y => resolutionProcedure(promise, y), promise.reject);
}else if (state === FULFILLED) {
//规范2.3.2.1 如果为fulfilled, 用相同的value fulfill promise
promise.resolve(x.value);
}else {
//规范2.3.2.2 如果为rejected, 用相同的reason reject promise
promise.reject(x.reason);
}
return;
}
//规范2.3.3 如果x为对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 规范2.3.3.1 获取x的then属性
const then = x.then;
if (typeof then === 'function') {
//规范2.3.3.3 如果then 为函数,调用then,以x为this值,传入resolvePromise和rejectPromise两个回调函数
then.call(x, resolvePromise, rejectPromise);
}else {
// x为普通对象和普通函数,直接resolve(x)
promise.resolve(x);
}
}catch(e) {
//规范2.3.3.3.4.1 调用then抛出异常时,如果resolvePromise或者rejectPromise已被调用,则忽略该异常
if (!resolvePromise.called && !rejectPromise.called) {
promise.reject(e);
}
}
}else {
// 规范2.3.4 x不为object或者function,直接resolve(x)
promise.resolve(x);
}
function resolvePromise(y) {
// 稍后实现
}
function rejectPromise(r) {
// 稍后实现
}
}
六、 resolvePromise、rejectPromise实现
function resolvePromise(y) {
//规范2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,
//则优先采用首次调用并忽略剩下的调用
if (!rejectPromise.called && !resolvePromise.called) {
// 给函数增加called属性,并设置为true,表明已经被调用
resolvePromise.called = true;
//规范2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
resolutionProcedure(promise, y);
}
}
function rejectPromise(r) {
//规范2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,
//则优先采用首次调用并忽略剩下的调用
if (!resolvePromise.called && !rejectPromise.called) {
rejectPromise.called = true;
//规范2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
promise.reject(r);
}
}