引言
Promise
出现解决了 js 中的回调地狱的问题,使代码更简洁,是 ES6 中的规范和重要特性。它的使用很简单,但你知道它是怎么样实现的吗~~
现在我们就来看一下 Promise 究竟是怎么样实现的 😄
- promise 规范
Promise 规范是 Promise 函数中需要遵循的规则,
ES6 中使用的 Promise,它就是遵循Promise/A+规范的。
既然是有规则可循的,那我们根据规则来一步步实现Promise
。
1.创建 Promise 类
看一下Promise
是如何使用的
1 2 3 4 5 6 7 8 9 10 11
| 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
的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
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 规范

- 根据规范可知
Promise
有三种状态 pending
(等待),fulfilled
(完成),rejected
(拒绝)。
- 当状态为
pending
时,Promise 可以变为fulfilled
或rejected
状态
- 当状态为
fulfilled
时,Promise 不能改变其状态;必须有值且不能改变
- 当状态为
rejected
时,Promise 不能改变其状态;必须有拒绝的原因且不能改变
根据Promise
规则,接着写刚刚创建的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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
的规范:

- 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 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| 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 方法执行失败例如
1 2 3 4 5 6 7 8
| 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
方法会被执行,所以需要用一个数据来保存这些方法
根据这两点,再来修改一些代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| 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) } }) }) } }
|
写好了,测试一下~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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 中实现的方法也补一下
1 2 3 4 5 6 7
| class MyPromise { catch = (reject) => { this.then(null, reject); }; }
|
1 2 3 4 5
| MyPromise.resolve = (value) => { return new MyPromise((resolve, reject) => { resolve(value); }); };
|
1 2 3 4 5
| MyPromise.resolve = (reason) => { return new MyPromise((resolve, reject) => { reject(reason); }); };
|
- 还有
all
,race
,finally(原型方法)
,其实都是根据Promise 中的原型方法和Promise 规则实现的,这里就不一一列举啦。需要了解的小伙伴可以自行去看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| 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 啦!😄