Promise
# Promise
[TOC]
# 一、Promise的使用
摘自知乎
// 订外卖就是一个Promise,Promise就是承诺的意思
// 和商家达成的承诺,无论是做好还是烧糊,都会给予答复。
function orderTakeout() {
// Promise 接收两个参数
// resolve 异步事件成功时调用
// reject 异步事件失败时调用
return new Promise((resolve, reject)=>{
let result = cook();
// 商家的反馈
if(result==='ok') {
resolve('sending');
}else {
reject('sorry');
}
});
}
// 商家厨房做饭,模拟概率事件
function cook() {
return Math.random()>0.5 ? 'ok' : 'sorry';
}
orderTakeout().then(res=>console.log(res))
.catch(res=>console.log(res));
// 等价于
// orderTakeout().then(res=>console.log(res), res=>console.log(res));
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
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
# 二、Promise流程图
# 2.1 Promise/A+
规范
三种状态
pending|fulfilled(resolved)|rejected
当处于
pending
状态的时候,可以转移到fulfilled(resolved)
或者rejected
状态当处于
fulfilled(resolved)
状态或者rejected
状态的时候,就不可变。必须有一个
then
异步执行方法,then
接受两个参数且必须返回一个promise。
// onFulfilled 用来接收promise成功的值
// onRejected 用来接收promise失败的原因
promise1=promise.then(onFulfilled, onRejected);
1
2
3
2
3
# 三、手写myPromise()
参考链接:https://juejin.im/post/5c6ad98e6fb9a049d51a0f5e (opens new window)
# 3.1 无异步,无链式调用
// 版本一
function myPromise(executor) {
let self = this;
self.status = "pending" //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
}
}
//捕获构造异常
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFullfilled, onRejected) {
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
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
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
// 测试
let p = new myPromise(function (resolve, reject) {
console.log('start')
resolve('data')
})
p.then(
(v) => {
console.log('success ' + v)
},
(v) => {
console.log('error ' + v)
}
)
console.log('end')
// start
// success data
// end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 3. 2 添加发布订阅模式
let p = new Promise(function (resolve, reject) {
console.log('start');
setTimeout(function(){
resolve('data')
},2000);
});
p.then(
(v) => {
console.log('success: ' + v)
},
(v) => {
console.log('error: ' + v)
}
);
p.then(
(v) => {
console.log('success: ' + v)
},
(v) => {
console.log('error: ' + v)
}
);
console.log('end');
// start
// end
// 两秒后
// success: data
// success: data
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
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
对于异步情况,当代码执行到p.then()时,resolve()会随着setTimeout放到异步任务队列中。
在此期间实例p的状态还是默认状态,p.then()不知道该执行哪个参数,那岂不是要干等setTimeout去执行?实际上,在不知道哪个回调会被执行的情况下,我们可以先把两个都执行了,并把它们保存起来(订阅),等要用的时候发布一下就好了。
function myPromise(executor){
...
// 使用数组是因为then方法可以调用多次
// 用来保存then 方法中,第一个参数
self.onResolvedCb = []
// 用来保存then 方法中,第二个参数
self.onRejectedCb = []
...
function resolve(value) {
...
self.onResolvedCb.forEach(fn => fn());
}
function reject(reason) {
...
self.onRejectedCb.forEach(fn => fn());
}
}
myPromise.prototype.then = function(onFulfilled, onRejected){
...
if(self.status === 'pending'){
// 订阅
self.onResolvedCb.push(function(){
onFulfilled(self.value)
})
self.onRejectedCb.push(function(){
onRejected(self.reason)
})
}
...
}
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
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
// 版本二
function myPromise(executor) {
let self = this;
self.status = "pending" //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
// 用来保存then 方法中,第一个参数
self.onResolvedCallbacks = [];
// 用来保存then 方法中,第二个参数
self.onRejectedCallbacks = [];
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
self.onResolvedCb.forEach(fn => fn());
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
self.onRejectedCb.forEach(fn => fn());
}
}
//捕获构造异常
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
if(self.status === 'pending'){
// 订阅
self.onResolvedCb.push(function(){
onFulfilled(self.value);
})
self.onRejectedCb.push(function(){
onRejected(self.reason);
})
}
}
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
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
# 3.3 添加链式调用
then()方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then()方法后再调用一个then方法。
myPromise.prototype.then = function(onFulfilled, onRejected){
let self = this
return new myPromise(function(resolve, reject){
if(self.status === 'resolved'){...}
if(self.status === 'rejected'){...}
if(self.status === 'pending'){...}
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
光返回新实例是不够的,还应该把本轮的参数传递给下一个then方法的回调函数中去。
# 3.3.1 对于then中函数返回值的处理 非Promise情况
myPromise.prototype.then = function(onFulfilled, onRejected){
...
if(self.status === 'resolved'){
try{
let x = onFulfilled(self.value)
resolve(x)
}catch(e){
reject(e)
}
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
myPromise.prototype.then = function(onFulfilled, onRejected){
let self = this
let promise2 = new myPromise(function(resolve, reject){
// then 函数的成功回调函数的执行结果 与 promise2的关系
if(self.status === 'resolved'){
try{
let x = onFulfilled(self.value)
resolve(x) // 这是 x 是常量的时候,但x可能是一个新的promise,
}catch(e){
reject(e)
}
}
if(self.status === 'rejected'){
try{
let x = onRejected(self.reason)
resolve(x)
}catch(e){
reject(e)
}
}
if(self.status === 'pending'){
self.onResolvedCb.push(function(){
try{
let x = onFulfilled(self.value)
resolve(x)
}catch(e){
reject(e)
}
})
self.onRejectedCb.push(function(){
try{
let x = onRejected(self.reason)
resolve(x)
}catch(e){
reject(e)
}
})
}
})
return promise2
}
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
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
# 3.3.2 对于then中函数返回值的处理 Promise情况
p.then(v=>{}); // 返回了一个新的Promise实例
1
myPromise.prototype.then = function(onFulfilled, onRejected){
let self = this
let promise2 = new myPromise(function(resolve, reject){
// then 函数的成功回调函数的执行结果 与 promise2的关系
if(self.status === 'resolved'){
try{
let x = onFulfilled(self.value)
// x可能是一个新的promise , 抽离一个函数来处理x的情况
// https://juejin.im/post/5b88e06451882542d733767a
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
}
if(self.status === 'rejected'){...}
if(self.status === 'pending'){...}
})
return promise2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function resolvePromise(promise2, x, resolve, reject) {
// 防止回调地狱
if(promise2 === x) {
return reject(new TypeError('循环引用'));
}
if((typeof x === 'object' || typeof x === 'function') && x){
try {
// 每一个Promise都会有then方法,用变量then存储
let then = x.then;
// 如果是function,就认为返回的是promise,否则就是一个普通值。
if (typeof then === 'fucntion') {
// 注意当前上下文,this不是x
then.call(x,(y) => {
resolve(y)
}, (e) => {
reject(e);
});
} else {
resolve(x);
}
} catch (error) {
reject(error);
}
}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
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
目前先到这吧~~~只判断了第一次是promise的情况~
// 版本三
function myPromise(executor) {
let self = this;
self.status = "pending" //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
// 用来保存then 方法中,第一个参数
self.onResolvedCb = [];
// 用来保存then 方法中,第二个参数
self.onRejectedCb = [];
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
self.onResolvedCb.forEach(fn => fn());
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
self.onRejectedCb.forEach(fn => fn());
}
}
//捕获构造异常
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
let promise2 = new myPromise(function(resolve, reject){
// then 函数的成功回调函数的执行结果 与 promise2的关系
if(self.status === 'resolved'){
try{
let x = onFulfilled(self.value);
// x可能是一个新的promise , 抽离一个函数来处理x的情况
// https://juejin.im/post/5b88e06451882542d733767a
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
}
if(self.status === 'rejected'){try{
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}}
if(self.status === 'pending'){// 订阅
self.onResolvedCb.push(function(){
onFulfilled(self.value);
})
self.onRejectedCb.push(function(){
onRejected(self.reason);
})}
})
return promise2
}
function resolvePromise(promise2, x, resolve, reject) {
// 防止回调地狱
if(promise2 === x) {
return reject(new TypeError('循环引用'));
}
if((typeof x === 'object' || typeof x === 'function') && x){
try {
// 每一个Promise都会有then方法,用变量then存储
let then = x.then;
// 如果是function,就认为返回的是promise,否则就是一个普通值。
if (typeof then === 'fucntion') {
// 注意当前上下文,this不是x
then.call(x,(y) => {
resolve(y)
}, (e) => {
reject(e);
});
} else {
resolve(x);
}
} catch (error) {
reject(error);
}
}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
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
# 3.4 添加异步
版本三有点乱,在版本二的基础上添加
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
setTimeout(()=>{
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
},0);
if(self.status === 'pending'){
// 订阅
self.onResolvedCallbacks.push(function(){
onFulfilled(self.value);
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason);
})
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试没毛病。
// 面试版本
function myPromise(executor) {
let self = this;
self.status = "pending" //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
// 用来保存then 方法中,第一个参数
self.onResolvedCallbacks = [];
// 用来保存then 方法中,第二个参数
self.onRejectedCallbacks = [];
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
self.onResolvedCb.forEach(fn => fn());
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
self.onRejectedCb.forEach(fn => fn());
}
}
//捕获构造异常
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
setTimeout(()=>{
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
},0);
if(self.status === 'pending'){
// 订阅
self.onResolvedCallbacks.push(function(){
onFulfilled(self.value);
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason);
})
}
}
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
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
# 四、promise的各种用法
https://github.com/sindresorhus/promise-fun
# 4.1 Promise对象实现Ajax操作
var request = (method, url, data) => {
return new Promise((resolve, reject) => {
var client = new XMLHttpRequest();
client.open(method, url);
client.onreadystatechange = handler;
client.send(data);
function handler() {
if (this.readyState === 4) return;
if (this.status <= 200 && this.status > 300 || this.status === 304) {
resolve(this.response);
}else {
reject(new Error(this.statusText));
}
}
});
};
request("GET","/get.json").then(
(json) => {
console.log(`Contents:${JSON.stringify(json)}`);
}, (error) => {
console.error(`Error:${error}`);
}
);
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
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
// 可以避免回调地狱
// 平常ajax是这样写
ajax({
success(){}
})
1
2
3
4
5
2
3
4
5
# 五、promise方法
# 5.1 Promise.all()
- 用于将多个Promise实例包装成一个新的Promise实例。
var p = Promise.all([p1, p2, p3]);
1