如何实现一个Promise
日期:2019-11-22 21:27:00
更新:2019-11-22 21:27:00
标签:前端, Javascript, ES6
分类:Javascript
出现解决了js中的回调地狱的问题,使代码更简洁,是ES6中的规范和重要特性。它的使用很简单,但你知道它是怎么样实现的吗~~ 现在我们就来看一下Promise究竟是怎么样实现的

引言
Promise出现解决了 js 中的回调地狱的问题,使代码更简洁,是 ES6 中的规范和重要特性。它的使用很简单,但你知道它是怎么样实现的吗~~
现在我们就来看一下 Promise 究竟是怎么样实现的 😄
- promise 规范
Promise 规范是 Promise 函数中需要遵循的规则,
ES6 中使用的 Promise,它就是遵循Promise/A+规范的。
既然是有规则可循的,那我们根据规则来一步步实现Promise。
1.创建 Promise 类
看一下Promise是如何使用的
const promise = new Promise((resolve, reject) => {
try {
resolve("123");
} catch (err) {
reject("error");
}
});
promise.then((msg) => {
console.log(msg);
});
- 首先它是一个构造方法,并且接收一个
function作为参数,
而这个function中有resolve和reject两个方法。resolve代表成功后返回的值,reject代表拒绝返回的原因
根据Promise的使用来创建一个叫MyPromise的类
class MyPromise {
constructor(callback) {
callback(this.resolve, this.reject);
}
resolve = (value) => {};
reject = (reason) => {};
}
var test = new MyPromise((resolve, reject) => {
console.log("my promise is running!");
});
2.三种状态
现在我们创建的类已经可以执行传入的方法了,但是它传入的resolve和reject方法是有什么用的呢?
我们接着看Promise 规范
A promise must be in one of three states: pending, fulfilled, or rejected.
When pending, a promise:
may transition to either the fulfilled or rejected state.
When fulfilled, a promise:
must not transition to any other state.
must have a value, which must not change.
When rejected, a promise:
must not transition to any other state.
must have a reason, which must not change.
- 根据规范可知
Promise有三种状态 pending(等待),fulfilled(完成),rejected(拒绝)。
- 当状态为
pending时,Promise 可以变为fulfilled或rejected状态
- 当状态为
fulfilled时,Promise 不能改变其状态;必须有值且不能改变
- 当状态为
rejected时,Promise 不能改变其状态;必须有拒绝的原因且不能改变
根据Promise规则,接着写刚刚创建的类:
const stateArr = ["pending", "fulfilled", "rejected"];
class MyPromise {
constructor(callback) {
this.state = stateArr[0];
this.value = null;
this.reason = null;
callback(this.resolve, this.reject);
}
resolve = (value) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.value = value;
}
};
reject = (reason) => {
if (this.state === stateArr[0]) {
this.state = stateArr[2];
this.reason = reason;
}
};
}
测试一下: 调用resolve后,状态变为fulfilled,再调用reject时,状态和值都不会改变,这样符合 Promise 规范.
3.then 方法
我们的MyPromise写到这里,他已经可以实现更新状态和传值了,但是它的值怎么样输出给我们的业务呢?
由Promise的使用可以看到,它是通过then方法来输出值的。then是是一个必要的方法,看一下then的规范:
A promise must provide a then method to access its current or eventual value or reason.
A promise’s then method accepts two arguments: promise.then(onFulfilled, onRejected)
- promise 必须提供一个
then方法去访问他的当前或最终的值或原因
- promise 中
then方法接收两个参数 onFulilled和onRejected
下面是关于onFulilled和onRejected的规范(部分)
onFulilled和onRejected两者都是一个可选的参数:
- 如果
onFulilled不是一个函数,它必须被忽视
- 如果
onRejected不是一个函数,它必须被忽视
- 如果
onFulilled是一个函数:
- 它必须在 fulfilled 时被调用,promise 方法中的
value作为第一个参数
- 它必须在 fulfilled 之前不被调用
- 它不能被多次调用
- 如果
onRejected是一个函数:
- 它必须在 rejected 时被调用,promise 方法中的
reason作为第一个参数
- 它必须在 rejected 之前不被调用
- 它不能被多次调用
- 在执行上下文堆栈仅包含平台代码之前,不能调用
onFulfilled或onRejected
onFulfilled和onRejected必须是一个函数
then可以在同一个 promise 中多次被调用
then 必须返回一个promise
根据 then 函数的规则,我们来设计这个 then 方法
const stateArr = ["pending", "fulfilled", "rejected"];
class MyPromise {
constructor(callback) {
this.state = stateArr[0];
this.value = null;
this.reason = null;
callback(this.resolve, this.reject);
}
resolve = (value) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.value = value;
}
};
reject = (reason) => {
if (this.state === stateArr[0]) {
this.state = stateArr[2];
this.reason = reason;
}
};
then = (onFulilled, onRejected) => {
onFulilled =
typeof onFulilled === "function" ? onFulilled : (value) => value;
onRejected =
typeof onRejected === "function" ? onRejected : (reason) => reason;
if (this.state === stateArr[1]) {
return new MyPromise((resolve, reject) => {
try {
const result = onFulilled(this.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
}
if (this.state === stateArr[2]) {
return new MyPromise((resolve, reject) => {
try {
const result = onRejected(this.reason);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
}
};
}
4.继续完善
至此,我们的MyPromise的已经基本可以运行了,但是现在有一个很严重的缺陷,如果遇到异步的请求时候,resolve不能按上下文执行,这会导致 then 方法执行失败例如
var test = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 2000);
}).then((msg) => {
console.log(msg);
return 456;
});
因为在调用then方法的时候,promise的状态还没有改变,而我们的then方法还没有处理 pending 状态的逻辑。 这导致执行异步方法的时候,then 方法不会返回任何东西
比如,在上面的例子中,javscript 已经把then方法执行了,但setTimeout中的方法还在eventloop中等待执行。
这样需要做的是:
- 将
then中的方法保存起来,等待resolve或reject执行后再调用刚刚保存的then中的方法
- 由于在这期间可能会有多个
then方法会被执行,所以需要用一个数据来保存这些方法
根据这两点,再来修改一些代码
constructor(callback) {
this.resolveArr = [];
this.rejectArr = [];
}
resolve = (value) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.value = value;
this.resolveArr.forEach(fun => fun(value))
}
}
reject = (reason) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.reason = reason;
this.rejectArr.forEach(fun => fun(reason))
}
}
then = (onFulilled, onRejected) => {
if (this.state === stateArr[0]) {
return new Promise((resolve, reject) => {
this.resolveArr.push((value) => {
try {
const result = onFulilled(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
this.rejectArr.push((value) => {
try {
const result = onRejected(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err)
}
})
})
}
}
写好了,测试一下
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 2000);
})
.then((msg) => {
console.log(msg);
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(456);
}, 2000);
});
})
.then((msg) => {
console.log(msg);
});
5.Promise 的其他方法
根据 Promise 规范实现的Promise大致已经完成啦,最后我们把 Promise 中实现的方法也补一下
class MyPromise {
catch = (reject) => {
this.then(null, reject);
};
}
MyPromise.resolve = (value) => {
return new MyPromise((resolve, reject) => {
resolve(value);
});
};
MyPromise.resolve = (reason) => {
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
- 还有
all,race,finally(原型方法),其实都是根据Promise 中的原型方法和Promise 规则实现的,这里就不一一列举啦。需要了解的小伙伴可以自行去看
const stateArr = ["pending", "fulfilled", "rejected"];
class MyPromise {
constructor(callback) {
this.state = stateArr[0];
this.value = null;
this.reason = null;
this.resolveArr = [];
this.rejectArr = [];
callback(this.resolve, this.reject);
}
resolve = (value) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.value = value;
this.resolveArr.forEach((fun) => fun(value));
}
};
reject = (reason) => {
if (this.state === stateArr[0]) {
this.state = stateArr[1];
this.reason = reason;
this.rejectArr.forEach((fun) => fun(reason));
}
};
then = (onFulilled, onRejected) => {
onFulilled =
typeof onFulilled === "function" ? onFulilled : (value) => value;
onRejected =
typeof onRejected === "function" ? onRejected : (reason) => reason;
if (this.state === stateArr[0]) {
return new MyPromise((resolve, reject) => {
this.resolveArr.push((value) => {
try {
const result = onFulilled(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
this.rejectArr.push((value) => {
try {
const result = onRejected(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
});
}
if (this.state === stateArr[1]) {
return new MyPromise((resolve, reject) => {
try {
const result = onFulilled(this.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
}
if (this.state === stateArr[2]) {
return new MyPromise((resolve, reject) => {
try {
const result = onRejected(this.reason);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
});
}
};
catch = (reject) => {
this.then(null, reject);
};
}
MyPromise.resolve = (value) => {
return new MyPromise((resolve, reject) => {
resolve(value);
});
};
MyPromise.resolve = (reason) => {
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
小结
这次我们了解了 promise 是如何实现的:
- 必须是构造函数
- 三种状态(pending,resolve,reject)
- then 方法(promise 中必须要有的方法)
从构造函数开始,到三种状态的实现,最后实现 then 方法一步步根据Promise规则来实现 Promise。了解完以后就可以在面试官面前手写一个 Promise 啦!😄