Promise 实现
基本结构:
class _Promise {
constructor(executor) {
this.state = "PENDING"; // 定义 Promise 状态
this.value = undefined; // 存储 promise 对应状态的值
this.fulfilledCallbacks = []; // 存储成功的回调
this.rejectedCallbacks = []; // 存储失败的回调
const resolve = () => {};
const reject = () => {};
executor(resolve,reject);
}
then(){}
catch(){}
}其中 resolvedCallbacks、rejectedCallbacks 分别处理 同一个 promise 实例注册多个 then 时对应执行的回调。
比如这种情况,promise 当 promise 实例 Fulfilled 时,所有注册的成功回调都要执行,Rejected 同理
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
// 注册的第一个 then
promise.then((value) => {
console.log(value); // 输出 1
return value + 1;
});
// 注册的第二个 then
promise.then((value) => {
console.log(value); // 输出 1
return value * 2;
});实现 resolve、reject
const resolve = (val) => {
// 保证回调函数执行顺序
setTimeout(() => {
this.value = val;
this.status = "FULFILLED";
// 执行当前实例上注册过的 所有回调
this.fulfilledCallbacks.forEach(f => f(this.value))
}, 0)
};
const reject = (reason) => {
setTimeout(() => {
this.value = reason;
this.status = "REJECTED";
this.rejectedCallbacks.forEach(f => f(this.value))
}, 0)
};其中使用 resolve 和 reject setTimeout 也可以不使用,Promise A+ 没有要求,只是优化策略。
实现 then
- 判断三种情况分别进行处理(PENDING|FULFILLED|REJECTED)
- 如果参数不是函数,要设置默认参数逻辑
- 返回一个新的 Promise 保证链式调用可行
- 要考虑 then 的回调函数返回值是 promise 的情况
当状态是 FULFILLED|REJECTED 时,说明 Promise 已经执行完成,按照规范异步执行onRejected,onFulfilled
PENDING 时 其实就是分别把 FULFILLED 和 REJECTED 的异步处理放进 对应 Callbacks 中等待状态更新后执行。
class _Promise {
// ...略
then (onFulfilled, onRejected) {
const _this = this;
// 默认值很重要 为了链式调用
// 如果 onFulfilled 不是函数,则其被忽略,同时向后传递异步结果 value。
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
// 如果 onRejected 不是函数,则其被忽略,直接抛出异常,交给后面的处理程序来处理。
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
if (_this.status === "REJECTED") {
return new _Promise((resolve, reject) => {
setTimeout(() => {
const x = onRejected(_this.value)
// 如果是 promise 得到其结果
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}, 0)
});
} else if (_this.status === "FULFILLED") {
return new _Promise((resolve, reject) => {
setTimeout(() => {
const x = onFulfilled(_this.value)
// 如果是 promise 得到其结果
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}, 0)
});
} else { // 处理 pending 状态
// 此时 onFulfilled 和 onRejected 外层不需要包裹 setTimeout 模拟异步执行
// 因为在 resolve 和 reject 执行他们的时候
// 已经是使用 setTimeout 进行异步执行了
const P = new _Promise((resolve, reject) => {
// 添加 resolve Callbacks
_this.fulfilledCallbacks.push(() => {
const x = onFulfilled(_this.value)
// 如果是 promise 得到其结果
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
});
// 添加 reject Callbacks
_this.rejectedCallbacks.push(() => {
const x = onRejected(_this.value)
// 如果是 promise 得到其结果
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
});
})
return P;
}
};
}
其中在 pending 状态下,将 then 中注册的回调添加进 Callbacks 数组时通过 包裹一层 setTimeout,将回调的执行添加进宏任务队列,这样可以保证在异步的情况下也能够获得 this.value。
promise 规范中是在添加进微任务队列中等待执行。
添加处理循环引用报错判断
当一个 Promise 对象在它的 then 方法中返回自身时,确实会形成一个无限循环调用,导致 **"Chaining cycle detected for promise" **
循环引用示例:
let promise = new Promise((resolve, reject) => {
resolve(1000);
})
let p1 = promise.then(value => {
console.log(value);
return p1;
})
p1.then(resolve => {
console.log(resolve); // 不会执行
}).catch(error => {
console.log(error.message); // 输出 "Chaining cycle detected for promise"
})添加判断,抽取成 resolvePromise 方法
- 判断回调函数的返回值x是否为Promise对象
- 如果x是Promise对象,则必须等待其状态改变后,新的Promise才能被resolve/reject。
- 如果x为普通值(非Promise),则直接将新Promise状态改为resolved,并将x作为该Promise对象的值传递下去。
if (this.status === "FULFILLED") {
return new _Promise((resolve, reject) => {
setTimeout(() => {
const x = onFulfilled(_this.value)
this.resolvePromise(_this, res, resolve, reject);
}, 0)
});
}
// 调用then或catch后返回的新 Promise 对象的内部判断
_Promise.prototype.resolvePromise = function (promise, x, resolve, reject) {
if (promise === x) { // 循环引用了
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 如果异步结果不是 Promise 类型,则直接解析为成功状态。
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}实现 catch
catch 相当于 then(null, onRejected);的简写形式。接受一个回调函数作为参数,该回调函数会接收到 Promise 抛出的错误信息,可以利用这个错误信息来进行相应的处理。此外,catch 方法返回一个新的 Promise 对象,并将该对象的状态标记为 resolved。
catch(onRejected) {
// 只处理异常情况,等同于 then(null, onRejected)
this.then(null, onRejected);
}添加错误处理
完整实现代码:
class _Promise {
constructor(executor) {
this.status = "PENDING";
this.value = undefined;
/**
* 存储成功和失败的回调函数
* 用于处理 多个promise.then() 或 多个 promise.catch() 的情况
* 比如
* promise.then()
* promise.then()
* promise.catch()
* promise.catch()
*/
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
const resolve = (val) => {
// 用于处理异步情况,宏任务永远能拿到 异步(微任务)传入的val
setTimeout(() => {
this.value = val;
this.status = "FULFILLED";
this.fulfilledCallbacks.forEach((f) => f(this.value));
});
};
const reject = (reason) => {
setTimeout(() => {
this.value = reason;
this.status = "REJECTED";
this.rejectedCallbacks.forEach((f) => f(this.value));
});
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
/**
* then 实现
* @param onFulfilled
* @param onRejected
* @returns {_Promise}
*/
then(onFulfilled, onRejected) {
const _this = this;
// 默认值很重要 为了链式调用
// 如果 onFulfilled 不是函数,则其被忽略,同时向后传递异步结果 value。
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : v => v;
// 如果 onRejected 不是函数,则其被忽略,直接抛出异常,交给后面的处理程序来处理。
onRejected =
typeof onRejected === "function" ? onRejected : e => { throw e };
if (_this.status === "FULFILLED") {
const P = new _Promise((resolve, reject) => {
// 按照规范 onFulfilled 异步执行
setTimeout(() => {
try {
const res = onFulfilled(_this.value);
this.resolvePromise(P, res, resolve, reject);
} catch (e) {
reject(e); // 错误处理 改变 promise 状态为 REJECTED
}
});
});
return P;
} else if (_this.status === "REJECTED") {
const P = new _Promise((resolve, reject) => {
// 按照规范 onRejected 异步执行
setTimeout(() => {
try {
const res = onRejected(_this.value);
_this.resolvePromise(P, res, resolve, reject);
} catch (e) {
reject(e);
}
});
});
return P;
} else { // 处理 pending 状态
const P = new _Promise((resolve, reject) => {
_this.fulfilledCallbacks.push(() => {
try {
let res = onFulfilled(_this.value);
_this.resolvePromise(P, res, resolve, reject);
} catch (r) {
reject(r);
}
});
_this.rejectedCallbacks.push(() => {
try {
let res = onRejected(_this.value);
_this.resolvePromise(P, res, resolve, reject);
} catch (r) {
reject(r);
}
});
})
return P;
}
}
/**
* catch实现
* @param onRejected
*/
catch(onRejected) {
// 只处理异常情况,等同于 then(null, onRejected)
this.then(null, onRejected);
}
}
/**
* 调用then或catch后返回的新 Promise 对象的内部判断
* @param promise
* @param x
* @param resolve
* @param reject
* @returns {*}
*/
_Promise.prototype.resolvePromise = function (promise, x, resolve, reject) {
if (promise === x) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 如果异步结果不是 Promise 类型,则直接解析为成功状态。
if (x instanceof _Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
Promise.resolve
1.传参为一个 Promise, 则直接返回它。
2.传参为一个 thenable 对象,返回的 Promise 会跟随这个对象,采用它的最终状态作为自己的状态。
3.其他情况,直接返回以该值为成功状态的promise对象。
Promise._resolve = function (p) {
if (p instanceof Promise) return p;
return new Promise((resolve, reject) => {
if (p && p.then && typeof p.then === "function") {
p.then(resolve, reject);
} else {
resolve(p);
}
});
};