在看到《前端面试之道》这本小册中关于手写Promise
部分,对此部分有比较大的兴趣,于是按照书中的例子加上自己的理解产生了这篇文章,如有理解不到之处,请大佬指出。文章篇幅较长,不喜勿喷
先来实现一个简易版的Promise
,代码较长,下面我会一一解释
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
--------------------------------------以上为1.
function MyPromise(fn) {
const that = this;
that.state = PENDING;
that.value = null;
that.resolvedCallbacks = [];
that.rejectedCallbacks = [];
----------------------------以上为2.1
// resolve 和 reject 函数
function resolve(value) {
// 判断当前状态是否为等待中
if (that.state === PENDING) {
that.state = RESOLVED;
that.value = value;
that.resolvedCallbacks.map((cb) => cb(that.value));
}
}
function reject(value) {
// 判断当前状态是否为等待中
if (that.state === PENDING) {
that.state = REJECTED;
that.value = value;
that.rejectedCallbacks.map((cb) => cb(that.value));
}
}
------------------------------以上为2.2
// 执行 fn 函数
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
-----------------------------以上为2.3
--------------------------------以上为2
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
onRejected =
typeof onRejected === "function"
? onRejected
: (r) => {
throw r;
};
if (that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled);
that.rejectedCallbacks.push(onRejected);
}
if (that.state === RESOLVED) {
onFulfilled(that.value);
}
if (that.state === REJECTED) {
onRejected(that.value);
}
};
-----------------------以上为3
以上主要分为3大部分,第二部分中又分为3个小部分
第一部分
- 首先我们创建了三个常量用于表示状态,对于经常使用的一些值都应该通过常量来管理,便于开发及后期维护。
promise
分别有pending
、resolved
、rejected
三种状态
第二部分
2.1
部分主要是对promise
中需要用到的变量进行初始化
1.1 在函数体内部首先创建了常量that
,因为代码可能会异步执行,用于获取正确的this
对象
1.2 一开始Promise
的状态应该是pending
1.3value
变量用于保存resolve
或者reject
中传入的值
1.4resolvedCallbacks
和rejectedCallbacks
用于保存then
中的回调,因为当执行完Promise
时状态可能还是等待中,这时候应该把then
中的回调保存起来用于状态改变时使用(这个地方第三部分的讲解中会涉及到)2.2
部分主要涉及的是resolve
和reject
函数
2.1 首先两个函数都得判断当前状态是否为等待中,因为规范规定只有等待态才可以改变状态
2.2 将当前状态更改为对应状态,并且将传入的值赋值给value
2.3 遍历回调数组并执行(异步方法)2.3
部分主要是对promise传入的异步方法进行执行,执行函数过程中会遇到错误,需要捕获错误并且执行reject
函数
第三部分
then
中可以传入两个方法,成功执行resolve
,失败执行reject
- 首先判断两个参数是否为函数类型,因为这两个参数是可选参数
- 当参数不是函数类型时,需要创建一个函数赋值给对应的参数
- 接下来就是一系列判断状态的逻辑,当状态不是等待态时,就去执行相对应的函数。如果状态是等待态的话,就往回调函数中
push
函数,比如如下代码就会进入等待态的逻辑
下面将用一个例子来讲解Promise
的执行过程
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
}).then(value => {
console.log(value)
})
在执行上面代码时,过程为:
- 首先
new Promise
,MyPromise
初始化函数内部参数,Promise
传入了一个函数fn
- 执行
fn
,传入resolve
和reject
两个方法 - 执行
then
,then
接收两个方法,如果不是pending
,就去执行响应的函数,现在为等待态,就将console.log
放入resolvedCallbacks
中,throw r
放入rejectedCallbacks
中 - 1秒后执行
setTimeout
中resolve
方法,当前状态为pending
,将状态修改为resolved
,将value
修改为resolve(1)
中传的值,遍历resolvedCallbacks
去执行其中的方法