# Promise 核心逻辑实现
# 分析
- Promise 就是一个类,在执行这个类时会传入一个执行器,并且这个执行器会立即执行
- Promise 有三种状态:等待(pending)、成功(fulfilled)、失败(rejected)
- Promise 的状态只能从 pending -> fulfilled 或者从 pending -> rejected,一旦改变就不可更改
- resolve 和 reject 函数就是用来更改状态的
- then 方法的作用是成功就调用成功的回调,失败就调用失败的回调,then 方法是定义在 promise 原型对象上的方法
- then 函数的成功回调中有一个参数表示成功之后的值,失败回调中参数表示失败的原因
# 简单实现
const PENDING = "pending"; // 等待的状态
const FULFILLED = "fulfilled"; // 成功状态
const REJECTED = "rejected"; // 失败状态
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
// promise的状态
status = PENDING;
// 成功的值
value = undefined;
// 失败的原因
reason = undefined;
// 成功的回调
successCallback = undefined;
// 失败的回调
failCallback = undefined;
resolve = (value) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为成功
this.status = FULFILLED;
// 保存成功的值
this.value = value;
// 有成功的回调就执行
this.successCallback && this.successCallback(this.value);
}
reject = (reason) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为失败
this.status = REJECTED;
// 保存失败的原因
this.reason = reason;
// 有失败的回调就执行
this.failCallback && this.failCallback(this.reason);
}
then(successCallback, failCallback) {
if (this.status === FULFILLED) {
successCallback(this.value);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback = successCallback;
this.failCallback = failCallback;
}
}
}
const promise = new MyPromise(function(resolve, reject) {
resolve("成功");
})
promise.then(function(value) {
console.log(value); // 成功
}, function(err) {
console.info(err);
})
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
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
# 解决一个 promise 多次 then 的情况
由于我们可能多次调用同一个 promise 的 then 方法,而上诉我们只处理了其中一次 callback,所以我们需要将其收集起来,依次执行
const PENDING = "pending"; // 等待的状态
const FULFILLED = "fulfilled"; // 成功状态
const REJECTED = "rejected"; // 失败状态
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject);
}
// promise的状态
status = PENDING;
// 成功的值
value = undefined;
// 失败的原因
reason = undefined;
// 成功的回调
successCallback = [];
// 失败的回调
failCallback = [];
resolve = (value) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为成功
this.status = FULFILLED;
// 保存成功的值
this.value = value;
// 有成功的回调就执行
while (this.successCallback.length) this.successCallback.unshift()(this.value);
}
reject = (reason) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为失败
this.status = REJECTED;
// 保存失败的原因
this.reason = reason;
// 有失败的回调就执行
while (this.failCallback.length) this.failCallback.unshift()(this.reason);
}
then(successCallback, failCallback) {
if (this.status === FULFILLED) {
successCallback(this.value);
} else if (this.status === REJECTED) {
failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
}
const promise = new MyPromise(function(resolve, reject) {
resolve("成功");
})
promise.then(function(value) {
console.log(value); // 成功
}, function(err) {
console.info(err);
})
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
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
# 实现 then 方法的链式调用和值传递
class MyPromise {
//.......
then(successCallback, failCallback) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 由于只有在 new MyPromise执行完毕后才能拿到promise2
// 所以我们需要将执行的代码转换成异步
setTimeout(() => {
let x = successCallback(this.value);
// 判断x的值是普通值还是promise对象
// 如果是普通值,就直接resolve
// 如果是promise对象,就查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是调用reject
resolvePromise(promise2, x, resolve, reject);
}, 0)
} else if (this.status === REJECTED) {
let err = failCallback(this.reason);
} else {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 判断如果返回的promise和当前的promise是相同的promise,就直接reject,避免循环调用
if (promise2 === x) {
return reject(new TypeError("Chaining cycle detected for promise #<Promise>"))
}
if (x instanceof MyPromise) {
// promise对象
// x.then(value => resolve(value), reason => reject(reason));
x.then(resolve, reject);
} else {
// 普通值
resolve(x);
}
}
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
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
# 处理异常
const PENDING = "pending"; // 等待的状态
const FULFILLED = "fulfilled"; // 成功状态
const REJECTED = "rejected"; // 失败状态
class MyPromise {
constructor(executor) {
// 处理执行器的报错
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
// promise的状态
status = PENDING;
// 成功的值
value = undefined;
// 失败的原因
reason = undefined;
// 成功的回调
successCallback = [];
// 失败的回调
failCallback = [];
resolve = (value) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为成功
this.status = FULFILLED;
// 保存成功的值
this.value = value;
// 有成功的回调就执行
while (this.successCallback.length) this.successCallback.unshift()();
}
reject = (reason) => {
// 如果状态不是pending就是直接返回
if (this.status !== PENDING) return;
// 将状态修改为失败
this.status = REJECTED;
// 保存失败的原因
this.reason = reason;
// 有失败的回调就执行
while (this.failCallback.length) this.failCallback.unshift()();
}
then(successCallback, failCallback) {
// 为了将then参数的值变成可选,并且可以让其值向下一个then传递
// 我们需要给它赋上默认的函数
successCallback ? successCallback : value => value;
failCallback ? failCallback : reason => { throw reason; };
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 处理successCallback报错
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return new TypeError("chaining cycle detected for promise <#Promise>")
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x)
}
}
const promise = new MyPromise(function(resolve, reject) {
resolve("成功");
})
promise.then(function(value) {
console.log(value); // 成功
}, function(err) {
console.info(err);
})
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
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
# Promise.all 方法
- Promise.all() 接收一个数组,元素可以是普通值也可以是 Promise 对象
- Promise.all()会依次执行这个数组中的内容,如果是普通值就直接返回,如果是 Promise 就执行并返回它的结果。
- 如果全部成功会返回一个数组,数组的值的顺序和接收的顺序一致
- 如果有一个失败,Promise.all()就会变为失败状态,并且返回第一次失败的结果
class MyPromise {
//...
static all (array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
const addData = (key, value) => {
result[index++] = value;
if (index === result.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => reject(reason));
} else {
addData(i, current);
}
}
})
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# resolve 方法
- Promise.resolve() 如果传入的是普通值,就将这个值作为成功的结果,返回给下一个 then
- 如果传入的是 Promise 对象就将它直接返回
class MyPromise {
//...
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve) => resolve(value));
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# finally 方法
- finally 方法接受一个回调函数,并且可以将上一个 then 的返回值,传递给下一个 then
- finally 方法的 return 是一个 Promise 对象,他的下一个 then 会等到它 return 的 Promise 执行完毕后,再执行
class MyPromise {
finally(callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value);
}, reason => {
return MyPromise.resolve(callback()).then(() => {throw reason; });
})
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# catch 方法
- catch 方法是 then 方法不传第一个参数的语法糖
class MyPromise {
catch(callback) {
return this.then(undefined, callback);
}
}
1
2
3
4
5
2
3
4
5
# 汇总
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
status = PENDING;
value = undefined;
reason = undefined;
successCallback = [];
failCallback = [];
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value;
while(successCallback.length) this.successCallback.unshift()();
}
reject = reason => {
if (this.status !== PENDING) return;
this.reason = reason;
this.status = REJECTED;
while(failCallback.length) this.failCallback.unshift()();
}
then(successCallback, failCallback) {
successCallback ? successCallback : value => value;
failCallback ? failCallback : reason => { throw reason; }
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
}
})
return promise2;
}
static all (array) {
let results = [];
let index = 0;
return new MyPromise((resolve, reject) => {
const addData = (key, value) => {
results[key] = value;
index++;
if (results.length === index) {
resolve(results);
}
}
for (let i = 0; i < 10; i++) {
let current = array[i];
if (current in instanceof MyPromise) {
current.then(value => addData(i, value), e => reject(e));
} else {
addData(i, current);
}
}
})
}
static race (array) {
let result = undefined;
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current in instanceof MyPromise) {
current.then(value => resolve(value), e => reject(e));
} else {
resolve(current);
}
}
})
}
static resolve(value) {
if(value instanceof MyPromise) return value;
return new MyPromise((resolve) => resolve(value))
}
static reject(reason) {
if (reason instanceof MyPromise) {
return reason.then((value) => { throw value; });
}
return new MyPromise((resolve, reject) => reject(reason))
}
finally (callback) {
this.then(value => {
return MyPromise.resolve(callback()).then(() => value);
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason; });
})
}
catch(callback) {
return this.then(undefined, callback);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return new TypeError("chaining cycle detected for promise #<Promise>");
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
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
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