# Promise/A+
ES6 的 Promise,相信很多人都知道。如果是在 ES5 呢?你如何自己实现一个 Promise?
ES6 采用的是 Promise/A+
规范,那么也采用一样的规范。Promise/A+
规范原文(英文) (opens new window),翻译的话,网上比较多,可以参考这篇翻译(中文) (opens new window)。
# 准备
使用promises-aplus-tests (opens new window)插件进行测试是否符合Promise/A+
规范。
npm install promises-aplus-tests -D
# 构造函数
// 等待态
const PENDING = "pending";
// 执行态
const FULFILLED = "fulfilled";
// 拒绝态
const REJECTED = "rejected";
class XPromise {
constructor(fn) {
// 状态
this.state = PENDING;
// 终值
this.value = undefined;
// 拒因
this.reason = undefined;
// 执行回调队列
this.onFulfilledCallbacks = [];
// 拒绝回调队列
this.onRejectedCallbacks = [];
// 执行的方法
const resolve = (value) => {
// 需要异步,这里使用宏任务
setTimeout(() => {
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
// 等待态->执行态
// 需要调用执行回调队列的所有方法
this.onFulfilledCallbacks.forEach((f) => f(this.value));
}
});
};
// 拒绝的方法
const reject = (reason) => {
// 需要异步,这里使用宏任务
setTimeout(() => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
// 等待态->拒绝态
// 需要调用拒绝回调队列的所有方法
this.onRejectedCallbacks.forEach((f) => f(this.reason));
}
});
};
// 如果报错,就调用拒绝方法
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
}
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
# then 方法
2.2.1、2.2.2、2.2.3 的实现。
class XPromise {
//...
then(onFulfilled, onRejected) {
// 2.2.1.1 不是函数就忽略
if (typeof onFulfilled !== "function") return;
// 2.2.1.2 不是函数就忽略
if (typeof onRejected !== "function") return;
// 这里已经确保了onFulfilled,onRejected是函数了,也满足了2.2.2,2.2.3
// 2.2.2,2.2.3 就把方法添加到队列里,promise完成后会自动调用
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
// 2.2.2 如果promise完成了,就直接调用
if (this.state === FULFILLED) onFulfilled(this.value);
// 2.2.3 如果promise完成了,就直接调用
if (this.state === REJECTED) onRejected(this.reason);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2.2.4 关于事件循环问题,这里用异步中的宏任务
class XPromise {
//...
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function") return;
if (typeof onRejected !== "function") return;
if (this.state === PENDING) {
// 2.2.4 为什么这里不用加?
// 你仔细看看XPromise构造函数,遍历调用前有没有包裹类似的东西?
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
if (this.state === FULFILLED) {
// 2.2.4 事件循环 这里也用setTimeout异步的宏任务
setTimeout(() => {
onFulfilled(this.value);
});
}
if (this.state === REJECTED) {
// 2.2.4 事件循环 这里也用setTimeout异步的宏任务
setTimeout(() => {
onRejected(this.reason);
});
}
}
}
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
2.2.7 需要返回一个promise
,意味着 2.2.1 要用另一种方式实现。
class XPromise {
//...
then(onFulfilled, onRejected) {
// *文档的promise2就是返回的promise,promise1就是自身
let promise;
// 需要返回 Promise
// if (typeof onFulfilled !== "function") return;
// if (typeof onRejected !== "function") return;
const isFunFulfilled = typeof onFulfilled === "function";
const isFunRejected = typeof onRejected === "function";
if (this.state === PENDING) {
promise = new Promise(() => {
if (isFunFulfilled) this.onFulfilledCallbacks.push(onFulfilled);
if (isFunRejected) this.onRejectedCallbacks.push(onRejected);
});
}
if (this.state === FULFILLED) {
promise = new Promise(() => {
setTimeout(() => {
if (isFunFulfilled) onFulfilled(this.value);
});
});
}
if (this.state === REJECTED) {
promise = new Promise(() => {
setTimeout(() => {
if (isFunRejected) onRejected(this.reason);
});
});
}
// 因为state只用3种状态,所以以上三个代表快会有一个执行,必然会返回promise
return promise;
}
}
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
2.2.7.1 如果onFulfilled
和onRejected
返回一个值x
,请运行 Promise 解决程序[[Resolve]](promise2, x)
class XPromise {
//...
then(onFulfilled, onRejected) {
let promise;
const isFunFulfilled = typeof onFulfilled === "function";
const isFunRejected = typeof onRejected === "function";
if (this.state === PENDING) {
promise = new Promise((resolve, reject) => {
if (isFunFulfilled) {
this.onFulfilledCallbacks.push((value) => {
const x = onFulfilled(value);
ResolutionProcedure(promise, x, resolve, reject);
});
}
if (isFunRejected) {
this.onRejectedCallbacks.push((reason) => {
const x = onRejected(reason);
ResolutionProcedure(promise, x, resolve, reject);
});
}
});
}
if (this.state === FULFILLED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isFunFulfilled) {
const x = onFulfilled(this.value);
ResolutionProcedure(promise, x, resolve, reject);
}
});
});
}
if (this.state === REJECTED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isFunRejected) {
const x = onRejected(this.reason);
ResolutionProcedure(promise, x, resolve, reject);
}
});
});
}
return promise;
}
}
// Promise 解决程序,为了方便。promise的resolve, reject方法一起传过来
function ResolutionProcedure(promise, x, resolve, reject) {
// 等会会讲到
}
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
2.2.7.2 如果onFulfilled
和onRejected
抛出一个异常e
,promise2
必须拒绝并将e
作为reason
。
class XPromise {
//...
then(onFulfilled, onRejected) {
let promise;
const isFunFulfilled = typeof onFulfilled === "function";
const isFunRejected = typeof onRejected === "function";
if (this.state === PENDING) {
promise = new Promise((resolve, reject) => {
if (isFunFulfilled) {
this.onFulfilledCallbacks.push((value) => {
try {
const x = onFulfilled(value);
ResolutionProcedure(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (isFunRejected) {
this.onRejectedCallbacks.push((reason) => {
try {
const x = onRejected(reason);
ResolutionProcedure(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
});
}
if (this.state === FULFILLED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
if (isFunFulfilled) {
const x = onFulfilled(this.value);
ResolutionProcedure(promise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
}
if (this.state === REJECTED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
if (isFunRejected) {
const x = onRejected(this.reason);
ResolutionProcedure(promise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
}
return promise;
}
}
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
2.2.7.3、2.2.7.4 又是关于onFulfilled
、onRejected
是否函数问题。需要和 2.2.1 结合一下。
class XPromise {
//...
then(onFulfilled, onRejected) {
let promise;
const isFunFulfilled = typeof onFulfilled === "function";
const isFunRejected = typeof onRejected === "function";
if (this.state === PENDING) {
promise = new Promise((resolve, reject) => {
this.onFulfilledCallbacks.push((value) => {
try {
// 是否函数判断、写到里面一层
if (isFunFulfilled) {
const x = onFulfilled(value);
ResolutionProcedure(promise, x, resolve, reject);
} else {
// 在构造函数里,如果状态完成或失败了,会执行相应的回调队列。
// 在这个方法内部,肯定是状态完成了,才执行的。
// 而且value也是this.value
resolve(value);
}
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push((reason) => {
try {
// 与上面同理
if (isFunRejected) {
const x = onRejected(reason);
ResolutionProcedure(promise, x, resolve, reject);
} else {
reject(reason);
}
} catch (e) {
reject(e);
}
});
});
}
if (this.state === FULFILLED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 是否函数判断、写到里面一层
if (isFunFulfilled) {
const x = onFulfilled(this.value);
ResolutionProcedure(promise, x, resolve, reject);
} else {
// 看看45行,状态是完成的了
resolve(this.value);
}
} catch (e) {
reject(e);
}
});
});
}
if (this.state === REJECTED) {
promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 与上面同理
if (isFunRejected) {
const x = onRejected(this.reason);
ResolutionProcedure(promise, x, resolve, reject);
} else {
reject(this.reason);
}
} catch (e) {
reject(e);
}
});
});
}
return promise;
}
}
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
# Promise 解决程序
你可以理解成,处理新的promise2
和上一个的promise1
的onFulfilled
返回值x
的关系。(不懂的话,看看下面)
# 理解
解决程序是干什么用的?先来看看下面的例子,v2
就是onFulfilled
的返回值吗?
const promise1 = new Promise((resolve) => resolve(1));
// const promise2 = promise1.then(onFulfilled, onRejected)
const promise2 = promise1.then((v1) => v1 + 2);
const promise3 = promise2.then((v2) => {
console.log(v2); // 3
});
2
3
4
5
6
如果返回一个Promise
,或者 thenable
(带有then
属性的对象)类型?还是原模原样打印出吗?
const promise1 = new Promise((resolve) => resolve(1));
const promise2 = promise1.then((v1) => {
const x = new Promise((resolve) => {
setTimeout(() => resolve(v1 - 1), 2000);
});
return x; // 返回一个Promise
});
const promise3 = promise2.then((v2) => {
// 明显不是打印[Promise]结构体出来,而是一个数字。而且需要更长的时间才显示。
console.log(v2); // 0
});
2
3
4
5
6
7
8
9
10
11
# 实现
2.3.1、2.3.2 的实现。
function ResolutionProcedure(promise, x, resolve, reject) {
// 2.3.1 如果promise和x引用同一个对象,则用TypeError作为reason拒绝promise
if (promise === x) {
reject(new TypeError("循环引用"));
return;
}
// 2.3.2
if (x instanceof XPromise) {
switch (x.state) {
// 2.3.2.1 如果x为pending状态,promise必须保持pending状态直到x成功或者失败
case PENDING:
// x.then(resolve, reject);
// 这里为什么不是上一行?你回想上面的理解,就是为了处理返回值的类型。
// 如果是x.then(resolve, reject),就等于没处理了,所以需要调用解决程序方法。
x.then((value) => {
ResolutionProcedure(promise, value, resolve, reject);
}, reject);
break;
// 2.3.2.2 如果x为完成状态,用相同的值完成promise
case FULFILLED:
resolve(x.value);
break;
// 2.3.2.3 如果x为失败状态,用相同的reason拒绝promise
case REJECTED:
reject(x.reason);
break;
}
}
}
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
2.3.3、2.3.3.1、2.3.3.2 的实现。
function ResolutionProcedure(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("循环引用"));
return;
}
if (x instanceof XPromise) {
switch (x.state) {
case PENDING:
x.then((value) => {
ResolutionProcedure(promise, value, resolve, reject);
}, reject);
break;
case FULFILLED:
resolve(x.value);
break;
case REJECTED:
reject(x.reason);
break;
}
} else if (x && ["object", "function"].includes(typeof x)) {
// 2.3.3 如果x是一个对象或函数
try {
// 2.3.3.1 让then为x.then
const then = x.then;
} catch (e) {
// 2.3.3.2 如果检索属性x.then的结果抛出一个异常e,用e作为reason拒绝promise
reject(e);
}
}
}
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
2.3.3.3、2.3.3.3.1、2.3.3.3.2 的实现
function ResolutionProcedure(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("循环引用"));
return;
}
if (x instanceof XPromise) {
switch (x.state) {
case PENDING:
x.then((value) => {
ResolutionProcedure(promise, value, resolve, reject);
}, reject);
break;
case FULFILLED:
resolve(x.value);
break;
case REJECTED:
reject(x.reason);
break;
}
} else if (x && ["object", "function"].includes(typeof x)) {
try {
const then = x.then;
if (typeof then === "function") {
// 2.3.3.3.1
const resolvePromise = (y) => {
ResolutionProcedure(promise, y, resolve, reject);
};
// 2.3.3.3.2
const rejectPromise = (r) => {
reject(r);
};
// 2.3.3.3 指针替换
then.call(x, resolvePromise, rejectPromise);
}
} catch (e) {
reject(e);
}
}
}
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
2.3.3.3.3 的实现。
function ResolutionProcedure(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("循环引用"));
return;
}
if (x instanceof XPromise) {
switch (x.state) {
case PENDING:
x.then((value) => {
ResolutionProcedure(promise, value, resolve, reject);
}, reject);
break;
case FULFILLED:
resolve(x.value);
break;
case REJECTED:
reject(x.reason);
break;
}
} else if (x && ["object", "function"].includes(typeof x)) {
let firstRun = false;
try {
const then = x.then;
if (typeof then === "function") {
const resolvePromise = (y) => {
if (firstRun) return;
firstRun = true;
ResolutionProcedure(promise, y, resolve, reject);
};
const rejectPromise = (r) => {
if (firstRun) return;
firstRun = true;
reject(r);
};
then.call(x, resolvePromise, rejectPromise);
}
} catch (e) {
if (firstRun) return;
firstRun = true;
reject(e);
}
}
}
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
2.3.3.4、2.3.4 的实现。
function ResolutionProcedure(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("循环引用"));
return;
}
if (x instanceof XPromise) {
switch (x.state) {
case PENDING:
x.then((value) => {
ResolutionProcedure(promise, value, resolve, reject);
}, reject);
break;
case FULFILLED:
resolve(x.value);
break;
case REJECTED:
reject(x.reason);
break;
}
} else if (x && ["object", "function"].includes(typeof x)) {
let firstRun = false;
try {
const then = x.then;
if (typeof then === "function") {
const resolvePromise = (y) => {
if (firstRun) return;
firstRun = true;
ResolutionProcedure(promise, y, resolve, reject);
};
const rejectPromise = (r) => {
if (firstRun) return;
firstRun = true;
reject(r);
};
then.call(x, resolvePromise, rejectPromise);
} else {
resolve(x); // 2.3.3.4 如果then不是函数,用x来完成promise
}
} catch (e) {
if (firstRun) return;
firstRun = true;
reject(e);
}
} else {
resolve(x); // 2.3.4 如果x不是对象或者函数,用x来完成promise
}
}
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
# 测试
根据promises-aplus-tests (opens new window)文档,加入以下内容。
XPromise.deferred = function() {
var result = {};
result.promise = new XPromise(function(resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
};
module.exports = XPromise;
2
3
4
5
6
7
8
9
10
11
// package.json
{
// ...
"main": "promise.js",
"scripts": {
"test": "promises-aplus-tests ./promise.js"
},
"devDependencies": {
"promises-aplus-tests": "^2.1.2"
}
}
2
3
4
5
6
7
8
9
10
11
测试结果:官方 872 个例子全部通过。
← 双向数据绑定 Typescript 类型 →