前言
在编程中,Promise 是一种常见的编程模式,它有效的帮助我们解决回调地狱问题。使我们能更优雅的编程,提高代码可读性和维护性。
我以前只会使用 Promise,并不知道它的实现源码,无法更好的理解 Promise。通过学习视频和查阅资料,深刻的理解该方法的源码。现在我将记录 Promise 源码实现的过程。
【实现 Promise 以下方法】
- resolve
- reject
- then
- catch
- all
- race
Promise 的三种状态
Promise 有 pending、fulfilled 和 rejected 三种状态,其中初始状态状态为 pending。
// 等待中
const PROMISE_PENDING_STATE = "pending";
// 成功
const PROMISE_FULFILLED_STATE = "fulfilled";
// 失败
const PROMISE_REJECTED_STATE = "rejected";
Promise 类方法
我们在调用创建 Promise 实例的时候,需要传入一个执行函数,这个函数接受两个参数,resolve 和 reject。通过 resolve 函数将 Promise 的状态由 pending 改为 fulfilled,通过 reject 函数将 Promise 的状态由 pending 改为 rejected。
下面我们定义 Promise 类方法,PromiseState 属性为 Promise 的状态,PromiseResult 属性存储的是 Promise 成功数据或失败的信息。
class Promise {
constructor(execute) {
this.PromiseState = PROMISE_PENDING_STATE;
this.PromiseResult = undefined;
// 通过bind改变this指向
execute(this.resolve.bind(this), this.reject.bind(this));
}
}
实现 resolve,reject
Promise 的状态转换是不可逆的,一旦由 pending -> fulfilled 或 pending -> rejected 就不能再改变 Promise 的状态。
resolve(result) {
// 当PromiseState为初始状态时,才允许修改
if (this.PromiseState === PROMISE_PENDING_STATE) {
this.PromiseState = PROMISE_FULFILLED_STATE;
this.PromiseResult = result;
}
}
reject(reason) {
// 当PromiseState为初始状态时,才允许修改
if (this.PromiseState === PROMISE_PENDING_STATE) {
this.PromiseState = PROMISE_REJECTED_STATE;
this.PromiseResult = reason;
}
}
执行函数抛出错误的时,Promise 的状态也将由 pending -> rejected, 需要通过 try catch 捕获错误。
class Promise {
constructor(execute) {
// ...
try {
execute(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
}
使用
const p1 = new Promise((resolve, reject) => {
resolve("success");
});
console.dir(p1);
const p1 = new Promise((resolve, reject) => {
reject("error");
});
console.dir(p1);
同步的 then 方法
当前实现只支持同步修改 Promise 状态。稍后再实现异步修改 Promise 状态。
then 用于处理 Promise 的结果,当 Promise 的结果确定后,then()方法会被调用。并且可以传入两个回调函数来处理 Promise 的结果。如果 Promise 的结果是 resolve,第一个调用函数会被调用并传入 resolve 的结果作为参数;如果 Promise 的结果是 reject,第二个函数会被调用并传入 reject 的错误信息作为参数。
then 方法返回一个新的 Promise,该 Promise 的状态由回调函数决定。如果回调函数返回的是一个 Promise 对象,那么新 Promise 的状态将与该 Promise 对象的状态相同。如果回调函数抛出错误,那么新 Promise 的状态将为 rejected,需要通过 try catch 捕获错误。
then(onResolved, onRejected) {
return new Promise((resolve, reject) => {
// 成功
if (this.PromiseState === PROMISE_FULFILLED_STATE) {
try {
const result = onResolved(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
// 失败
if (this.PromiseState === PROMISE_REJECTED_STATE) {
try {
const result = onRejected(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
})
}
由于处理成功和失败的回调做的事情都一样,只有执行的函数不一样,可以将处理成功和失败的回调封装为一个公共方法,以便重复使用。
then(onResolved, onRejected) {
return new Promise((resolve, reject) => {
// 封装的公共方法
const callback = (fn) => {
try {
const result = fn(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
};
// 成功
if (this.PromiseState === PROMISE_FULFILLED_STATE) {
callback(onResolve);
}
// 失败
if (this.PromiseState === PROMISE_REJECTED_STATE) {
callback(onRejected);
}
})
}
使用
const p1 = new Promise((resolve, reject) => {
resolve("success");
}).then(
(res) => {
console.log(res); // success
return "success----2";
},
() => {
// ....
}
);
console.dir(p1);
const p1 = new Promise((resolve, reject) => {
reject("error");
}).then(
() => {
// ....
},
(err) => {
console.log(err); // error
return "error---2";
}
);
console.dir(p1);
异步的 then 方法
上面代码都是通过同步修改 Promise 的状态,原生的 Promise 是支持异步修改 Promise 状态的,我们需要在 Promise 类中定义一个 callbacks 属性,用于存储当 Promise 状态改变后需要执行的回调方法。当 Promise 状态由 pending -> fulfilled 或 pending -> rejected 时,循环执行 callbacks 存储的回调方法,使其支持异步修改 Promise 的状态。
Promise 类添加 callbacks 属性
class Promise {
constructor(execute) {
// ...
this.callbacks = [];
}
}
then 方法处理异步回调
then(onResolved, onRejected) {
return new Promise((resolve, reject) => {
// ....
// 等待中
if (this.PromiseState === PROMISE_PENDING_STATE) {
// 添加异步回调
this.callbacks.push({
onResolved: () => {
callback(onResolved);
},
onRejected: () => {
callback(onRejected);
},
});
}
})
}
resolve,reject 方法异步执行
resolve(result) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
// ...
// 循环执行成功回调
this.callbacks.forEach((cb) => {
cb.onResolved(this.PromiseResult);
});
}
}
reject(reason) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
// ...
// 循环执行失败回调
this.callbacks.forEach((cb) => {
cb.onRejected(this.PromiseResult);
});
}
}
使用
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
}, 2000);
}).then(
(res) => {
console.log(res); // 2秒后输出success
return "success----2";
},
() => {
// ...
}
);
const p1 = new Promise((resolve, reject) => {
reject("error");
}).then(
() => {
// ....
},
(err) => {
console.log(err); // 2秒后输出error
return "error---2";
}
);
优化 then 方法
在 Promise 中,then 方法是异步执行的。为了确保 then 方法在同步任务完成后执行,我们可以通过 setTimeout 方法将 then 方法的执行放到宏任务中执行。这样,在同步任务执行完毕后,then 方法才会被调用。
未使用 setTimeout 优化
new Promise((resolve, reject) => {
console.log(1);
resolve("success");
}).then(
(res) => {
console.log(3);
return "success----2";
},
() => {
// ...
}
);
console.log(2);
使用 setTimeout 优化
then 方法
then(onResolved, onRejected) {
return new Promise((resolve, reject) => {
// 成功
if (this.PromiseState === PROMISE_FULFILLED_STATE) {
setTimeout(() => {
callback(onResolved);
});
}
// 失败
if (this.PromiseState === PROMISE_REJECTED_STATE) {
setTimeout(() => {
callback(onRejected);
});
}
})
}
resolve,reject 方法
resolve(result) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
// ...
setTimeout(() => {
this.callbacks.forEach((cb) => {
// ...
});
});
}
}
reject(reason) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
// ...
setTimeout(() => {
this.callbacks.forEach((cb) => {
// ...
});
});
}
}
结果:
new Promise((resolve, reject) => {
console.log(1);
resolve("success");
}).then(
(res) => {
console.log(3);
return "success----2";
},
() => {
// ...
}
);
console.log(2);
onResolved,onRejected 可选
Promise 中的 then 方法回调参数都是可选的,当调用 then 方法未传参数时,需要给默认值。
then(onResolved, onRejected) {
if (typeof onResolved !== "function") {
onResolved = (result) => {
return result;
};
}
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
// ...
}
catch 方法
当返回的 Promise 状态为 reject 时,可以使用 catch 方法捕获错误信息。
catch(onRejected) {
return this.then(null, onRejected);
}
Promise.resolve,Promise.reject
Promise.resolve 方法返回一个 Promise 对象,该 Promise 的状态由回调函数决定。如果回调函数返回的是一个 Promise 对象,那么新 Promise 的状态将与该 Promise 对象的状态相同。如果回调函数抛出错误,那么新 Promise 的状态将为 rejected,需要通过 try catch 捕获错误。
Promise.reject 方法返回一个 Promise 对象,该 Promise 的状态为 rejected。
static resolve(result) {
return new Promise((resolve, reject) => {
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
});
}
static reject(result) {
return new Promise((resolve, reject) => {
reject(result);
});
}
使用
const p1 = Promise.resolve(100);
console.dir(p1);
const p1 = Promise.rejected(0);
console.dir(p1);
Promise.all
Promise.all 方法接收一个 Promise 数组,返回一个新的 Promise 对象。该 Promise 对象的状态由数组中的元素决定。如果数组中所有元素的 PromiseState 状态都为 fulfilled,则 Promise 对象的状态为 fulfilled,PromiseResult 为数组中所有成功数据的集合。如果数组中至少有一个元素的 PromiseState 为 rejected,则 Promise 对象的状态为 rejected,PromiseResult 为该元素对应的错误信息。
为了解决异步操作的问题,我们定义 result 数组,用于接收 Promise 数组中元素成功的集合,等待数组中的所有 Promise 都完成并返回一个结果数组。
为了确保结果数组中的元素顺序,可以在循环中使用索引来指定成功 Promise 成功结果在 result 数组中的下标位置。
static all(promises) {
let result = [];
let count = 0;
return new Promise((resolve, reject) => {
for (let i = 0; i length; i++) {
promises[i].then(
(res) => {
result[i] = res;
count++;
if (count === promises.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
}
});
}
Promise.race
Promise.race 方法接收一个 Promise 数组,返回一个新的 Promise 对象。该 Promise 对象的状态由数组中第一个返回结果的元素决定。
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(reason) => {
reject(reason);
}
);
}
});
}
完整代码
const PROMISE_PENDING_STATE = "pending";
const PROMISE_FULFILLED_STATE = "fulfilled";
const PROMISE_REJECTED_STATE = "rejected";
class Promise {
constructor(execute) {
this.PromiseState = PROMISE_PENDING_STATE;
this.PromiseResult = undefined;
this.callbacks = [];
try {
execute(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(result) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
this.PromiseState = PROMISE_FULFILLED_STATE;
this.PromiseResult = result;
setTimeout(() => {
this.callbacks.forEach((cb) => {
cb.onResolved(this.PromiseResult);
});
});
}
}
reject(reason) {
if (this.PromiseState === PROMISE_PENDING_STATE) {
this.PromiseState = PROMISE_REJECTED_STATE;
this.PromiseResult = reason;
setTimeout(() => {
this.callbacks.forEach((cb) => {
cb.onRejected(this.PromiseResult);
});
});
}
}
then(onResolved, onRejected) {
if (typeof onResolved !== "function") {
onResolved = (result) => {
return result;
};
}
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
return new Promise((resolve, reject) => {
const callback = (fn) => {
try {
const result = fn(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
};
// 成功
if (this.PromiseState === PROMISE_FULFILLED_STATE) {
setTimeout(() => {
callback(onResolved);
});
}
// 失败
if (this.PromiseState === PROMISE_REJECTED_STATE) {
setTimeout(() => {
callback(onRejected);
});
}
// 等待中
if (this.PromiseState === PROMISE_PENDING_STATE) {
this.callbacks.push({
onResolved: () => {
callback(onResolved);
},
onRejected: () => {
callback(onRejected);
},
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(result) {
return new Promise((resolve, reject) => {
if (result instanceof Promise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
});
}
static reject(result) {
return new Promise((resolve, reject) => {
reject(result);
});
}
static all(promises) {
let result = [];
let count = 0;
return new Promise((resolve, reject) => {
for (let i = 0; i length; i++) {
promises[i].then(
(res) => {
result[i] = res;
count++;
if (count === promises.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
}
});
}
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(reason) => {
reject(reason);
}
);
}
});
}
}
文章来源于互联网:Promise实现原理