本文介绍参考[PromiseA+]规范来实现一个符合规范的Promise库。

上面是ES6+实现的Promise核心方法,其整体结构也可以通过下面的打印查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 01-打印Promise类的内容(静态方法) */
console.dir(Promise)

/* 打印输出(已经省略部分内容) */
// length: 1 期望形参数量((resolve,reject)=>{})
// name: "Promise" 类(构造函数)的名字
// prototype: Promise 原型对象
// then: ƒ then() then处理函数
// catch: ƒ catch() catch处理函数
// finally: ƒ finally() 完成的处理函数
// constructor: ƒ Promise() 原型的构造器属性
// race: ƒ race() 异步任务并发先执行完
// reject: ƒ reject() 包装为reject
// resolve: ƒ resolve() 包装为resolve
// all: ƒ all() 异步任务并发都执行完
// allSettled: ƒ allSettled()
// Symbol(Symbol.species): (...)
// Symbol(Symbol.toStringTag): "Promise"

Promises/A+ 规范约定的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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* 核心注解 */
/* 1、Promise应该被设计为一个类(构造函数) */
/* 2、Promise存在三种状态,分别是pending(等待)、rejected(失败) 和 resolved(成功)。*/
/* 3、Promise类(构造函数)接收一个“拥有两个函数参数的函数”作为参数,我们可以称之为执行器函数(executor)立即执行。*/
/* 4、Promise类(构造函数)内部应该以私有函数的方式来是实现reject和resolve函数。 */
/* 5、Promise内部考虑到异步任务的执行(譬如定时器)Promise状态无法立即完成等待->成功|失败的切换,使用注册/订阅模式*/
/* 6、Promise的then方法处理失败、成功、等待态(如果存在异步任务)的Promise后续任务。 */
/* 7、Promise的then方法应该实现链式调用,实现的策略是总是返回一个新的Promise对象 */

const PENDING = "PENDING";
const RESOLVED = "RESOLVED";
const REJECTED = "REJECTED";

function resolvePromise(promise, x, resolve, reject) {

/* 1、死循环处理 */
if (promise === x) {
reject(new TypeError("# Chaining cycle detected for promise #<Promise>"))
}

let called = false;
/* 2、区分返回值是基本值和(Promise)的情况*/
if ((typeof x === "object" && x != null) || typeof x === "function") {
try {
let then = x.then;
if (typeof then === "function") {
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject); /* 递归调用 */
}, r => {
if (called) return;
called = true;
reject(r);
})
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}

class Promise {
constructor(executor) {
this.status = PENDING;
this.value = this.reason = undefined;
this.rejectedCallBacks = [];
this.resolvedCallBacks = [];

/* reject 和 resolve 应该被实现为私有函数 */
let resolve = (val) => {

if (val instanceof Promise) {
return val.then(resolve, reject);
}

if (this.status === PENDING) {
this.status = RESOLVED;
this.value = val;
this.resolvedCallBacks.forEach(fn => fn());
}
}

let reject = (val) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = val;
this.rejectedCallBacks.forEach(fn => fn());
}
}

/* 执行器函数应该立即执行,并进行异常处理 */
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
onRejected = typeof onRejected === "function" ? onRejected : e => { throw e }

let promise = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);

}

if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}

if (this.status === PENDING) {
this.rejectedCallBacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})

this.resolvedCallBacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
})
return promise;
}
}

/* 基准测试 */
Promise.defer = Promise.deferred = function() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}

module.exports = Promise;

规范基准测试

1
2
3
npm install promises-aplus-tests g
cd dist
promises-aplus-tests Promise.js

Promise还有一些诸如catch和resolve等方法,下面简单给出它们的实现代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Promise{
/* .... */
catch (errCallBack) {
return this.then(null, errCallBack); /* 为了支持链式调用,此处需要return */
}
static resolve(data) {
return new Promise((resolve, reject) => {
resolve(data)
})
}
static reject(err) {
return new Promise((resolve, reject) => {
reject(err);
})
}
finally(callBack) {
return this.then((value) => {
return Promise.resolve(callBack()).then(() => value);
}, reason => {
return Promise.resolve(callBack()).then(() => { throw reason });
})
}
}