手写 Promise
花了一天的时间写了这篇文章,一步一步实现一个 Promise,如果哪里有问题请大家多多指教
一、初始化 Promise 类
Promise 接收一个函数,函数内有两个参数,第一个参数是成功的回调,第二个参数是错误的回调
class ToyPromise {
constructor(handler) {
// 注意:this 的指向是由函数执行的位置决定的
handler(this._resolve.bind(this), this._reject.bind(this));
}
_resolve() {}
_reject() {}
}
let p = new ToyPromise((resolve, reject) => {
console.log(1);
// 注意:this 的指向是由函数执行的位置决定的,这里的 this 指向的是 window
resolve();
});
二、添加 then 方法
then 方法也接收两个参数,第一个参数是 resolve 执行的函数,第二个参数是 reject 或出现错误执行的函数
then 方法并不会立即执行传入的函数而是需要等待当前 ToyPromise 调用 resolve 或 reject 方法,们这里需要先把传入的参数保存到一个指定的位置,在 ToyPromise 调用 resolve 或 reject 方法以后再去执行 - 事件注册
class ToyPromise {
constructor(handler) {
// 数组:队列 - 先注册的,在调用 resolve 方法的使用,先执行的 FIFO
this.resolvedHandler = [];
this.rejectedHandler = [];
handler(this._resolve.bind(this), this._reject.bind(this));
}
_resolve() {
let handler;
// 执行注册的函数
while ((handler = this.resolvedHandler.shift())) {
handler();
}
}
_reject() {}
then(resolvedHandler, rejectedHandler) {
// 先把传入的 resolveHandler 保存到一个指定的位置
this.resolvedHandler.push(resolvedHandler);
this.rejectedHandler.push(rejectedHandler);
}
}
let p = new ToyPromise((resolve, reject) => {
resolve();
});
p.then(() => {
console.log("第一个 then -- 1");
});
p.then(() => {
console.log("第一个 then -- 2");
});
这个时候操作就会发现 then 并未执行,因为 resolve, 和 then 方法都是同步的,then 内的函数并未添加到数组中,resolve 已经执行结束了,而原生 Promise 的 then 方法内的函数执行则是异步的,所以我们就要对 resolve 方法进行一些更改,让 resolve 的代码异步执行
三、then 的异步操作
_resolve() {
setTimeout(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
handler();
}
}, 0);
}
我们对 resolve 内的代码包裹在定时器内从而让里面的代码异步执行,但是 setTimeout 属于宏任务,而原生的 Promise 的 then 方法则是微任务,微任务在同步渲染后, DOM 渲染前执行,宏任务在 DOM 渲染后执行,所以我们就要在对 resolve 方法进行一些更改,让 resolve 的代码变成微任务
// 宏任务
setTimeout(() => {
console.log("宏任务");
});
// postMessage
// MutationObserver
// 微任务
let ob = new MutationObserver((list) => {
console.log("微任务");
});
// 观察者:观察 DOM 元素的变化
ob.observe(document.body, {
attributes: true,
});
document.body.setAttribute("random", Math.random());
通过上述代码,我们可以看到 MutationObserver 比 setTimeout 先执行,所以我们可以通过 MutationObserver 来更改 resolve 方法
// 创建 observer 方法, 接收一个回调函数,在 DOM 变化时执行
observer(callback) {
let ob = new MutationObserver((list) => {
callback();
});
// 观察者:观察 DOM 元素的变化
ob.observe(document.body, {
attributes: true,
});
document.body.setAttribute("random", Math.random());
}
_resolve() {
this.observer(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
handler();
}
});
}
四、then 方法接收参数
_resolve(val) {
this.observer(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
// 将 resolve 接收的参数,传入 then 的回调函数中
handler(val);
}
});
}
五、then 方法的链式调用
1. 返回正常值
then 方法链式调用,我们现在 then 方法现在没有返回值,默认的返回值 undefined,而我们想要链式调用 then 方法,所以我们就应当让 then 方法返回一个 Promise 对象来去调用 then 方法,而不是 undefiend;
then(resolvedHandler, rejectedHandler) {
return new ToyPromise((resolve, reject) => {
this.resolvedHandler.push((val) => {
resolvedHandler(val);
// 调用下一个 then
resolve();
});
});
}
let p = new ToyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 100);
});
p.then((val) => {
console.log("第一个 then -- 1", val);
}).then(() => {
console.log("链式调用第二个 then");
});
上一个 then 函数内的回调函数的返回值,是下一个 then 函数的回调函数的参数
then(resolvedHandler, rejectedHandler) {
// this.rejectedHandler.push(rejectedHandler);
return new ToyPromise((resolve, reject) => {
this.resolvedHandler.push((val) => {
let res = resolvedHandler(val);
// 调用 then 方法,并传递参数
resolve(res);
});
});
}
2. 返回 Promise 对象
如果 then 函数内的回调函数的返回值是一个 Promise 对象,那么这个 Promise 对象不再是下个 then 方法的参数,而是调用下个 then 方法 Promise 对象。
then(resolvedHandler, rejectedHandler) {
return new ToyPromise((resolve, reject) => {
this.resolvedHandler.push((val) => {
let res = resolvedHandler(val);
// 如果 then 方法返回的是 ToyPromise 对象
if (res instanceof ToyPromise) {
// 给返回的是 ToyPromise 对象 添加 then 方法, 传入当前的这个 Promise 的 resolve 方法,因为下一个 then 方法注册在当前这个对象上,而不是在返回的 Promise 上
res.then(resolve);
return;
}
resolve(res);
});
});
}
res 是 then 方法的回调函数 的返回值,如果 res 是 ToyPromise 对象,我们就要 res 添加 then 方法, 并传入当前的 这个 ToyPromise 对象的 resolve 方法,因为链式调用的第二个 then 方法注册在当前的这个 ToyPromise 对象上,而不是在 res 上,所以我们要给 res 添加 then 方法来执行链式调用的第二个 then 方法
let p = new ToyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 100);
});
p.then((val) => {
console.log("第一个 then -- 1", val);
return new ToyPromise((resolve, reject) => {
resolve("123");
});
}).then(() => {
console.log("链式调用第二个 then");
});
3. 返回一个包含 then 属性的对象
我们只需要判断 res 是否是含有 then 属性的对象,如果是直接执行就可以
then(resolvedHandler, rejectedHandler) {
return new ToyPromise((resolve, reject) => {
this.resolvedHandler.push((val) => {
let res = resolvedHandler(val);
if (res instanceof ToyPromise) {
// 给 res 添加 then 方法, resolve 后执行
res.then(resolve);
return;
}
// res 是否是含有 then 属性的 对象
if (typeof res === "object" && res.then) {
res.then();
return;
}
resolve(res);
});
});
}
六、添加状态
Promise 必然处于以下几种状态之一:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
注:状态只能更改一次
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(handler) {
this.resolvedHandler = [];
this.rejectedHandler = [];
// 初始状态
this.status = ToyPromise.PENDING;
handler(this._resolve.bind(this), this._reject.bind(this));
}
_resolve(val) {
// 判断状态是否为初始状态
if (this.status !== ToyPromise.PENDING) return;
// 更改状态
this.status = ToyPromise.FULFILLED;
this.observer(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
handler(val);
}
});
}
_reject(val) {
if (this.status !== ToyPromise.PENDING) return;
this.status = ToyPromise.REJECTED;
this.observer(() => {
let handler;
while ((handler = this.rejectedHandler.shift())) {
handler(val);
}
});
}
七、catch 方法和错误处理
try catch 捕获异常
注意:then 执行过程中发生异常状态就会变成 rejected, 而 catch 函数执行过程中不发生异常状态就会变回 fulfilled
constructor(handler) {
this.resolvedHandler = [];
this.rejectedHandler = [];
// 初始化状态
this.status = ToyPromise.PENDING;
try {
handler(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
}
}
then(resolvedHandler, rejectedHandler) {
return new ToyPromise((resolve, reject) => {
// 成功状态的注册的函数
this.resolvedHandler.push((val) => {
// 判断参数是否为函数
if (typeof resolvedHandler === "function") {
// try catch 捕获异常
try {
let res = resolvedHandler(val);
if (res instanceof ToyPromise) {
// 给 res 添加 then 方法, resolve 后执行
res.then(resolve, reject);
return;
}
// thenable 含有 then 属性的 对象
if (typeof res === "object" && res.then) {
res.then();
return;
}
resolve(res);
} catch (error) {
// 发生异常执行错误的回调
reject(error);
}
}
});
// 失败状态的注册的函数
this.rejectedHandler.push((val) => {
// 判断参数是否为函数
let res;
if (typeof rejectedHandler === "function") {
// try catch 捕获异常
try {
res = rejectedHandler(val);
if (res instanceof ToyPromise) {
// 给 res 添加 then 方法, resolve 后执行
res.then(resolve, reject);
return;
}
// thenable 含有 then 属性的 对象
if (typeof res === "object" && res.then) {
res.then();
return;
}
resolve(res);
} catch (error) {
// 发生异常执行错误的回调
reject(error);
}
}
});
});
}
catch(rejectedHandler) {
return this.then(undefined, rejectedHandler);
}
八、 finally 方法
constructor(handler) {
// 数组:队列 - 先注册的,在调用resolve方法的时候,先执行, FIFO
this.resolvedHandler = [];
// 注册在调用 reject 方法的时候,执行的函数
this.rejectedHandler = [];
// 注册在调用 finally 方法的时候,执行的函数
this.finallyHandler = [];
// 初始化状态
this.status = ToyPromise.PENDING;
try {
handler(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
}
}
_resolve(val) {
// 判断是否为初始化状态
if (this.status !== ToyPromise.PENDING) return;
this.status = ToyPromise.FULFILLED;
this.observer(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
handler(val);
}
// 执行 finally 的函数
this._finally();
});
}
_reject(val) {
// 判断是否为初始化状态
if (this.status !== ToyPromise.PENDING) return;
this.status = ToyPromise.REJECTED;
this.observer(() => {
let handler;
while ((handler = this.rejectedHandler.shift())) {
handler(val);
}
// 执行 finally 的函数
this._finally();
});
}
// 执行 finally 函数
_finally() {
let handler;
// 因为每一个独立的Promise只处理一次任务,所以注册的回调取出以后就不再需要了
while ((handler = this.finallyHandler.shift())) {
handler();
}
}
// 注册finally 函数
finally(finallyHandler) {
this.finallyHandler.push(finallyHandler);
}
九、Promise.resolve
static resolve(val) {
return new ToyPromise((resolve, reject) => {
resolve(val);
});
}
ToyPromise.resolve(123).then((val) => {
console.log(val);
});
十、Promise.all
static all(arr) {
let len = arr.length;
let values = [];
let n = 0;
return new ToyPromise((resolve, reject) => {
for (let i = 0; i < len; i++) {
arr[i].then((val) => {
n++;
values.push(val);
if (len === n) {
resolve(values);
}
});
}
});
}
let p1 = new ToyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 100);
});
let p2 = new ToyPromise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 1000);
});
let p3 = new ToyPromise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 300);
});
ToyPromise.all([p1, p2, p3]).then((vals) => {
console.log(vals);
});
十一、ToyPromise
class ToyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(handler) {
// 数组:队列 - 先注册的,在调用resolve方法的时候,先执行, FIFO
this.resolvedHandler = [];
// 注册在调用 reject 方法的时候,执行的函数
this.rejectedHandler = [];
// 注册在调用 finally 方法的时候,执行的函数
this.finallyHandler = [];
// 初始化状态
this.status = ToyPromise.PENDING;
try {
handler(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
}
}
_resolve(val) {
// 判断是否为初始化状态
if (this.status !== ToyPromise.PENDING) return;
this.status = ToyPromise.FULFILLED;
this.observer(() => {
let handler;
while ((handler = this.resolvedHandler.shift())) {
handler(val);
}
this._finally();
});
}
_reject(val) {
// 判断是否为初始化状态
if (this.status !== ToyPromise.PENDING) return;
this.status = ToyPromise.REJECTED;
this.observer(() => {
let handler;
while ((handler = this.rejectedHandler.shift())) {
handler(val);
}
this._finally();
});
}
_finally() {
let handler;
// 因为每一个独立的Promise只处理一次任务,所以注册的回调取出以后就不再需要了
while ((handler = this.finallyHandler.shift())) {
handler();
}
}
observer(callback) {
let ob = new MutationObserver((list) => {
callback();
});
// 观察者:观察 DOM 元素的变化
ob.observe(document.body, {
attributes: true,
});
document.body.setAttribute("random", Math.random());
}
then(resolvedHandler, rejectedHandler) {
return new ToyPromise((resolve, reject) => {
// 成功状态的注册的函数
this.resolvedHandler.push((val) => {
// 判断参数是否为函数
if (typeof resolvedHandler === "function") {
try {
let res = resolvedHandler(val);
if (res instanceof ToyPromise) {
// 给 res 添加 then 方法, resolve 后执行
res.then(resolve, reject);
return;
}
// thenable 含有 then 属性的 对象
if (typeof res === "object" && res.then) {
res.then();
return;
}
resolve(res);
} catch (error) {
reject(error);
}
}
});
// 失败状态的注册的函数
this.rejectedHandler.push((val) => {
// 判断参数是否为函数
let res;
if (typeof rejectedHandler === "function") {
try {
res = rejectedHandler(val);
if (res instanceof ToyPromise) {
// 给 res 添加 then 方法, resolve 后执行
res.then(resolve, reject);
return;
}
// thenable 含有 then 属性的 对象
if (typeof res === "object" && res.then) {
res.then();
return;
}
resolve(res);
} catch (error) {
alert(error);
reject(error);
}
}
});
});
}
catch(rejectedHandler) {
return this.then(undefined, rejectedHandler);
}
finally(finallyHandler) {
this.finallyHandler.push(finallyHandler);
}
static resolve(val) {
return new ToyPromise((resolve, reject) => {
resolve(val);
});
}
static all(arr) {
let len = arr.length;
let values = [];
let n = 0;
return new ToyPromise((resolve, reject) => {
for (let i = 0; i < len; i++) {
arr[i]
.then(
(val) => {
n++;
values.push(val);
if (len === n) {
resolve(values);
}
},
(error) => {
console.log(error);
}
)
.catch((error) => {
console.log(error);
reject(error);
});
}
});
}
}