###promise原理系列目录:

promise实现原理(一)promise.then

promise实现原理(二)promise.catch

promise实现原理(三)promise.finally

promise实现原理(四)promise.all与promise.race

promise实现原理(五)promise.allSettled与promise.any

promise实现原理(六)promise.resolve与promise.reject

promise实现最终版!合成代码

#js中,日常进行异步操作时,通常会使用会 promise来控制异步操作,那么promise的原理是什么呢。

首先我们来看一下,es6标准中,支持哪些方法

1
2
3
4
5
6
7
8
9
10
//标准提到,一个promise只有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
Promise.prototype.then();
Promise.prototype.catch();
Promise.prototype.finally();
Promise.all();
Promise.race();
Promise.allSettled();
Promise.any();
Promise.resolve();
Promise.reject();

我们来看一下,promise的原理,
首先,promise是一个构造函数,可以用new关键字来创建一个promise对象
也就是 ,包含一个其实状态pending
按照es6文档中标明的,一般使用方法为

1
2
3
4
5
6
new Promise((resolve,reject)=>{
console.log('aa');
resolve('bb')
}).then((data)=>{
console.log('bb');
})

此函数为立即执行的,所以我们的promise 需要支持一个立即执行的方法

1
2
3
4
5
6
function myPromise(callback) {
callback&&callback()
}
new myPromise(()=>{
console.log(1)
})

这样就完成了一个可以用new关键字创建,且立即执行参入回调的函数myPromise了。

这个立即执行的方法,可以支持使用resolve报完成,以及使用reject报失败且.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
function myPromise(callback) {
var self = this;
self.status = 'pending';//创建当前状态为pending
self.data = null;//此变量为保存成功状态的数据使用
self.callbackObj = {};//回调对象,用于存放.then中的回调

self.doCallback=function(){//执行回调函数
if(self.status == 'resolved'){//取构造函数中保存的data,传入callback方法里
self.callbackObj.resolveCallback&&self.callbackObj.resolveCallback(self.data)
}else if(self.status == 'rejected'){
self.callbackObj.rejectCallBack&&self.callbackObj.rejectCallBack(self.data)
}
}
function resolve(value) {//声明resolve方法,支持报成功
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
self.doCallback()
}
}
function reject(value) {
if(self.status === 'pending') {
self.status = 'rejected';
self.data = value;
self.doCallback()
}
}
setTimeout(function(){
callback&&callback(resolve,reject);
})
}
//根据es6文档,此处的promise,原型链上需要增加一个.then方法,来支持调用结果后,执行的方法,此方法也接收一个回调函数
myPromise.prototype.then = function(resolveCallback,rejectCallBack){//.then存入待执行事件,不然如果是异步操作,则未完成时候.then就执行了
this.callbackObj.resolveCallback=resolveCallback;
this.callbackObj.rejectCallBack=rejectCallBack;
}

//此时,myPromise便支持了使用resolve和reject汇报调用结果,且使用.then方法接收结果数据
new myPromise((resolve,reject)=>{
console.log(1)
resolve('resolved')
}).then((data)=>{
console.log(data)
})

至此,我们已经完成了一个支持异步使用resolve,reject来汇报结果的简单的promise。

#但是众所周知,promise对象是支持链式调用的,我们使用现在已完成的对象,链式调用的话,会发生奇怪的问题

1
2
3
4
5
6
7
8
9
new myPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('resolve')
},1000)
}).then((data)=>{
console.log(data,'then1');//这条被跳过去了
}).then((data)=>{
console.log(data,'then2');//resolve,then2
})

说明我们的.then方法是有问题的,支持链式调用,说明应该把.then的回调都存起来,状态完成后再一起出发,我们修改一下.then方法,成功回调和失败的储存回调的Object变成一个数组,制作一个事件队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
myPromise.prototype.then = function(resolveCallback,rejectCallBack){//.then存入待执行事件,执行的时候,循环执行一下待执行事件队列
this.callbackObj.resolveCallback?this.callbackObj.resolveCallback.push(resolveCallback):this.callbackObj.resolveCallback=[resolveCallback];
this.callbackObj.rejectCallBack?this.callbackObj.rejectCallBack.push(rejectCallBack):this.callbackObj.rejectCallBack=[rejectCallBack];
return this
}


myPromise.doCallback=function(){//执行回调函数
if(this.status == 'resolved'){//取构造函数中保存的data,传入callback方法里
if(this.callbackObj.resolveCallback&&this.callbackObj.resolveCallback.length>0){
this.callbackObj.resolveCallback.forEach((item)=>{
item(this.data)
})
}
}else if(this.status == 'rejected'){
if(this.callbackObj.rejectCallBack&&this.callbackObj.rejectCallBack.length>0){
this.callbackObj.rejectCallBack.forEach((item)=>{
item(this.data)
})
}
}
}

接下来在执行,链式调用.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
63
function myPromise(callback) {
var self = this;
self.status = 'pending';//创建当前状态为pending
self.data = null;//此变量为保存成功状态的数据使用
self.callbackObj = {};//回调对象,用于存放.then中的回调

self.doCallback=function(){//执行回调函数
let callBackArr = []
if(self.status == 'resolved'){//取构造函数中保存的data,传入callback方法里
callBackArr = self.callbackObj.resolveCallback;
}else if(self.status == 'rejected'){
if(self.callbackObj.rejectCallBack[0]){
callBackArr = self.callbackObj.rejectCallBack;
}else{
callBackArr = [self.callbackObj.catchCallBack];
}
}
if(callBackArr&&callBackArr.length>0){
callBackArr.forEach((item)=>{
item(self.data)
})
}
}
function resolve(value) {//声明resolve方法,支持报成功
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
self.doCallback()
}
}
function reject(value) {
if(self.status === 'pending') {
self.status = 'rejected';
self.data = value;
self.doCallback()
}
}
setTimeout(function(){
callback&&callback(resolve,reject);
})
}
//根据es6文档,此处的promise,原型链上需要增加一个.then方法,来支持调用结果后,执行的方法,此方法也接收一个回调函数
myPromise.prototype.then = function(resolveCallback,rejectCallBack){//.then存入待执行事件,不然如果是异步操作,则未完成时候.then就执行了
this.callbackObj.resolveCallback?this.callbackObj.resolveCallback.push(resolveCallback):this.callbackObj.resolveCallback=[resolveCallback];
this.callbackObj.rejectCallBack?this.callbackObj.rejectCallBack.push(rejectCallBack):this.callbackObj.rejectCallBack=[rejectCallBack];
return this
}
myPromise.prototype.catch=function(catchCallBack){
this.callbackObj.catchCallBack=catchCallBack;
}
//此时,myPromise便支持了使用resolve和reject汇报调用结果,且使用.then方法接收结果数据
new myPromise((resolve,reject)=>{
console.log(1)
resolve('resolved')
}).then((data)=>{
console.log(data,'then1')
}).then((data)=>{
console.log(data,'then2')
}).then((data)=>{
console.log(data,'then3')
}).then((data)=>{
console.log(data,'then4')
})

下期再完善其他方法