Promise写了这么多,或许还有很多地方有些模糊,今天我们来手把手实现一个Promise,从根源看一下Promise到底是什么。
为便于代码阅读,整体采用es6方案实现。
1.框架结构
新建一个MyPromise类,按照mdn文档一一列举Promise实例属性及静态属性。
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = MyPromise.PENDING;
this.value = null; // 储存成功后的值
this.reason = null; // 储存失败后的值
this.onFulfilledCallbacks = []; // 储存成功状态函数列表
this.onRejectedCallbacks = []; // 储存失败状态的函数列表
try {
executor(this.resolve.bind(this), this.reject.bind(this)); // 将this指回MyPromise
} catch (err) {
this.reject(err);
}
}
then(onFulfilled,onRejected) {}
catch() {}
finally() {}
resolve(value) {}
reject(value) {}
static get [Symbol.species]() {
return this;
}
static resolve() {}
static reject() {}
static all() {}
static race() {}
static allSettled() {}
static any() {}
}
2.实现resolve和reject
resolve接收成功后的值value,获取到值后改变Promise状态为FULFILLED,同时储存兑现值,方便在then中调用。具体如下:
reject同理。
resolve(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.reason= reason;
}
}
3.实现then函数
具体见注释
// 规范 2.2 接收两个参数
then(onFulfilled, onRejected) {
const f = onFulfilled;
const r = onRejected;
// 2.2.1 如果onFulfilled,onRejected不是函数,则忽略他们,按照原值传递
if (typeof onFulfilled !== "function") {
onFulfilled = (value) => value;
}
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
// 2.2.7 then方法需要返回一个promise
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === MyPromise.FULFILLED) {
// 规范2.2.4 这个确保 onFulfilled 和 onRejected 都在下一轮的事件循环中(一个新的栈)被异步调用。
setTimeout(() => {
try {
// 2.2.7.3 如果 onFulfilled 不是一个函数,并且 promise1 状态是 fulfilled,那么 promise2 一定会接受到与 promse1 一样的值 value
// 简单来说就是不是一个函数时,进行值传递
if (typeof f !== "function") {
resolve(this.value);
} else {
const x = onFulfilled(this.value);
// 进入Promise 处理程序
this.resolvePromise(promise2, x, resolve, reject);
}
} catch (err) {
reject(err);
}
});
} else if (this.state === MyPromise.REJECTED) {
setTimeout(() => {
try {
if (typeof r !== "function") {
reject(this.reason);
} else {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}
} catch (err) {
reject(err);
}
});
// 如果执行then方法时,还是pending状态,将回调函数保存起来
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof f !== "function") {
resolve(this.value);
} else {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof r !== "function") {
reject(this.reason);
} else {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
}
});
return promise2;
}
4.修改resolve和reject
如果前一个promise尚未兑现,调用了then方法,我们将回调函数储存起来,等待兑现后从数组中取出执行。所以在resolve和reject方法中需要进行如下修改
在进行保存时已经进行了异步处理,这里直接同步执行即可。
resolve(value) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(this.value));
}
}
reject(reason) {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(this.reason));
}
}
5.实现Promise 处理程序
promiseA+规范2.3中对处理程序进行了详细说明,按照规范一步一步执行即可
resolvePromise(promise, x, resolve, reject) {
// 规范 2.3.1 如果返回的 promise1 和 x 是指向同一个引用(循环引用),则抛出错误
if (promise === x) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 2.3.2 如果 x 是一个 promise 实例,递归处理
if (x instanceof MyPromise) {
x.then((y) => {
this.resolvePromise(promise, y, resolve, reject);
}, reject);
}
// 2.3.3 此外,如果 x 是个对象或函数类型
else if (typeof x === "object" || typeof x === "function") {
if (x === null) {
return resolve(x);
}
let then;
try {
then = x.then;
} catch (error) {
return reject(error);
}
// 2.3.3.3 如果 then 是函数类型
if (typeof then === "function") {
let called = false;
try {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} catch (error) {
if (called) return;
reject(error);
}
} else {
resolve(x);
}
} else {
resolve(x);
}
}
6.其他实例方法
catch(onRejected) {
this.then(null, onRejected);
}
finally(fn) {
return this.then(
(value) => {
return MyPromise.resolve(fn()).then(() => value);
},
(error) => {
return MyPromise.resolve(fn()).then(() => {
throw error;
});
}
);
}
7.实现静态方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}
static all(promiseList) {
return new MyPromise((resolve, reject) => {
const resList = [];
if (promiseList.length === 0) {
return resolve(resList);
}
promiseList.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(res) => {
result[index] = res;
if (result.length === promiseList.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promiseList) {
const promise = new MyPromise((resolve, reject) => {
if (promiseList.length === 0) {
return resolve();
}
promiseList.forEach((promise) => {
MyPromise.resolve(promise).then(
(value) => resolve(value),
(reason) => reject(reason)
);
});
});
}
static allSettled(promiseList) {
return new MyPromise((resolve) => {
const result = [];
if (promiseList.length === 0) {
return resolve(result);
}
promiseList.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(val) => {
result[index] = {
status: "fulfilled",
value: val,
};
if (result.length === promiseList.length) {
return resolve(result);
}
},
(reason) => {
result[index] = {
status: "rejected",
reason: reason,
};
if (result.length === promiseList.length) {
return resolve(result);
}
}
);
});
});
}
static get [Symbol.species]() {
return this;
}
8.测试
到这里,我们的代码就完成了。接下来使用promise规范对我们的代码进行验证
添加如下代码
static deferred() {
const result = {};
result.promise = new MyPromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
module.exports = MyPromise;
项目配置
// 初始化项目
npm init -y
// 安装promise测试插件
npm i promises-aplus-tests -D
// package.json文件配置下脚本执行部分
"scripts": {
"test": "promises-aplus-tests promiseKB.js(填入自己开发的promise的名字)"
},
// 执行
npm run test
完美通过!!