上一篇文章我们认识了 Promise 的基本用法,现在来尝试手动来实现一下简单的 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
/*创建三个变量来表示状态*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(fn) {
/* that 保存 this ,避免 this 指向问题*/
const that = this;
/*value 用来保存 resolve 或 reject 中传入的值*/
that.value = null;
/*默认状态*/
that.status = PENDING;
/*
*用于保存 then 中的回调
*当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
that.fulfilledCallback = [];
that.rejectedCallback = [];

function resolve(value) {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}

function reject(value) {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}

/*执行回调*/
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}

/*
*考虑到所有的实例都要用到then方法,then方法得放在promise的原型链上。
*当状态是PENDING状态时,该做什么?不执行回调,那就将回调方法分别放入不同的栈内,等待调用。
*当状态为FULFILLED或者REJECTED时,则执行响应的方法即可。
*/
myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
_this.fulfilledCallback.push(() => {
resolveFun(_this.value);
});

_this.rejectedCallback.push(() => {
rejectFun(_this.value);
});
}

if (_this.status === FULFILLED) {
resolveFun(_this.value);
}

if (_this.status === REJECTED) {
rejectFun(_this.value);
}
};

let pro = new myPromise((resolve, reject) => {
console.log("myPromise");
resolve("data");
});

pro.then((res) => {
console.log(res);
});

好了,一个简易的 Promise 就完成了,我们来看一下结果:

优化

resolve 和 reject 的改造

根据 promise+规范改造 promise,传给 then 的应该是个 promise。
resolve 和 reject 的改造:

  • 对于 resolve 函数来说,首先需要判断传入的值是否为 Promise 类型
  • 为了保证函数执行顺序,需要将两个函数体代码使用 setTimeout 包裹起来
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
function resolve(value) {
/*判断value值是否为Promise类型*/
if (value instanceof myPromise) {
return value.then(resolve, reject);
}

/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}, 0);
}

function reject(value) {
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}, 0);
}

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
myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
/*新增一个变量 promise2,因为每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象*/
let promise2 = null;
resolveFun = typeof resolveFun === "function" ? resolveFun : (res) => res;
rejectFun =
typeof rejectFun === "function"
? rejectFun
: (val) => {
throw val;
};
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
return (promise2 = new myPromise((resole, reject) => {
_this.fulfilledCallback.push(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
});

_this.rejectedCallback.push(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}

rejectFun(_this.value);
});
}));
}

if (_this.status === FULFILLED) {
return (promise2 = new myPromise((resole, reject) => {
setTimeout(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}

if (_this.status === REJECTED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
};

如果 val 处于等待状态,Promise 需保持为等待状态直至 val 被执行或拒绝
如果 val 处于其他状态,则用相同的值处理 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
resultPromise(promise, val, resolve, reject){
/*为了防止回调地狱的情况,需要判断一下 promise2 与当前结果的关系
* 如果相等,这说明出现回调地狱,就抛出一个错误
*/
if(promise === val){
return reject(new TypeError('循环引用') )
}
/*判断val类型*/
if (val instanceof myPromise) {
val.then(function (value) {
resultPromise(promise, value, resolve, reject)
}, reject)
}
/*创建一个变量 bool 用于判断是否已经调用过函数*/
let bool = false;
if(val !== null && (typeof val === 'object' || typeof val === 'function') ){
try{
/*因为每个 promsie 都会有一个 then 方法,用变量 then 来保存它;如果出现错误,直接执行 reject 方法*/
let then = val.then;
/*判断then方法的类型,如果是 function;就认为返回的是一个 promise,否则就是一个普通的值,直接调用 resolve 方法*/
if( typeof then === 'function'){
/*让then方法执行,判断执行的结果,如果成功就走 resolve ;失败就走 reject
* 因为当前上下文的 this 指向的并不是 val,所以通过 call 方法改变this指向 val
*/
then.call(val, (data)=>{
if(bool) return;
bool = true;
/*通过递归解析,重复执行,直到返回的结果不是一个 promise 为止*/
resultPromise(promise2, data, resolve, reject)
},(e)=>{
if(e) return;
bool = true;
reject(e)
})
}else {
resolve(val)
}
} catch(e){
if(bool) return;
bool = true;
reject(e)
}
}else {
/*如果当前的值不是一个函数也不是一个对象,那说明是一个普通值,就直接进入下一次的成功方法*/
resolve(val)
}
}

完整代码

以上就是修改的内容了,来将代码整理一下:

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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*创建三个变量来表示状态*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(fn) {
/* that 保存 this ,避免 this 指向问题*/
const that = this;
/*value 用来保存 resolve 或 reject 中传入的值*/
that.value = null;
/*默认状态*/
that.status = PENDING;
/*
*用于保存 then 中的回调
*当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
that.fulfilledCallback = [];
that.rejectedCallback = [];

function resolve(value) {
/*判断value值是否为Promise类型*/
if (value instanceof myPromise) {
return value.then(resolve, reject);
}

/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}, 0);
}

function reject(value) {
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}, 0);
}

/*执行回调*/
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}

myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
/*新增一个变量 promise2,因为每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象*/
let promise2 = null;
resolveFun = typeof resolveFun === "function" ? resolveFun : (res) => res;
rejectFun =
typeof rejectFun === "function"
? rejectFun
: (val) => {
throw val;
};
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
return (promise2 = new myPromise((resole, reject) => {
_this.fulfilledCallback.push(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
});

_this.rejectedCallback.push(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}

rejectFun(_this.value);
});
}));
}

if (_this.status === FULFILLED) {
return (promise2 = new myPromise((resole, reject) => {
setTimeout(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}

if (_this.status === REJECTED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
};

function resultPromise(promise, val, resolve, reject) {
/*为了防止回调地狱的情况,需要判断一下 promise2 与当前结果的关系
* 如果相等,这说明出现回调地狱,就抛出一个错误
*/
if (promise === val) {
return reject(new TypeError("循环引用"));
}
/*判断val类型*/
if (val instanceof myPromise) {
val.then(function (value) {
resultPromise(promise, value, resolve, reject);
}, reject);
}
/*创建一个变量 bool 用于判断是否已经调用过函数*/
let bool = false;
if (val !== null && (typeof val === "object" || typeof val === "function")) {
try {
/*因为每个 promsie 都会有一个 then 方法,用变量 then 来保存它;如果出现错误,直接执行 reject 方法*/
let then = val.then;
/*判断then方法的类型,如果是 function;就认为返回的是一个 promise,否则就是一个普通的值,直接调用 resolve 方法*/
if (typeof then === "function") {
/*让then方法执行,判断执行的结果,如果成功就走 resolve ;失败就走 reject
* 因为当前上下文的 this 指向的并不是 val,所以通过 call 方法改变this指向 val
*/
then.call(
val,
(data) => {
if (bool) return;
bool = true;
/*通过递归解析,重复执行,直到返回的结果不是一个 promise 为止*/
resultPromise(promise2, data, resolve, reject);
},
(e) => {
if (e) return;
bool = true;
reject(e);
}
);
} else {
resolve(val);
}
} catch (e) {
if (bool) return;
bool = true;
reject(e);
}
} else {
/*如果当前的值不是一个函数也不是一个对象,那说明是一个普通值,就直接进入下一次的成功方法*/
resolve(val);
}
}

执行结果

现在来使用一下,看下结果:

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
function p1() {
let p1 = new myPromise((resolve, reject) => {
resolve(111);
});
return p1;
}
function p2() {
let p2 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(222);
console.log("第二次");
}, 2000);
});
return p2;
}

function p3() {
let p3 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(333);
console.log("第三次");
}, 3000);
});
return p3;
}

p1()
.then(
(res) => {
console.log(res);
return p2();
},
(err) => {
console.log("err", err);
}
)
.then((res) => {
console.log(res);
return p3();
})
.then((res) => {
console.log(res);
return "直接返回数据";
})
.then((res) => {
console.log(res);
});

打印结果如下:

🔨Promise(三):拓展方法实现