实现Promise

手写Promise

参考资料:掘金,手写Promise

阮一峰promise

this的指向问题

1.先看个Promise例子

1
2
3
4
new Promise(function (resolve, reject) {
console.log(1);
resolve('resolve');
})
1) 看到Promise接收一个参数,并且有三种状态 pending,fulfilled,rejected

调用resolve 状态从pending => fulfilled

调用reject 状态从pending => rejected

并且不可逆转

2)先声明个promise函数,接受个一个函数,有个状态pending,resolve和reject方法都接受一个参数,并且要保存这个参数。并且有pending的状态改变
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
function MyPromise(exector) {
var self = this;
self.status = 'pending';
self.value = '';
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved';
self.value = value;
console.log('resolved');
}
}

function reject(value) {
if (self.status == 'pending') {
self.status = 'rejected';
self.value = value;
console.log('rejected');
}
}
exector(resolve, reject);
}

//然后调用
new MyPromise(function (resolve, reject) {
console.log(1);
resolve('resolve');
})
//打印出
//1
//resolved

2.实现Promise.prototype.then

1)先看then方法
1
2
3
4
5
6
7
new Promise(function (resolve, reject) {
console.log(1);
resolve('resolve');
}).then(function(data){console.log(data)},function(err){console.log(err)})
//打印出
//1
//resolve
2)then方法实现:它接受两个参数,onFulfilled和onRejected,两个方法都有接收参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MyPromise.prototype.then = function(onFulfilled,onRejected){
if(this.status == 'resolved') {//这里this指向Promise
onFulfilled(this.value);
}

if(this.status == 'rejected') {
onRejected(this.value);
}
}
//调用
new MyPromise(function (resolve, reject) {
console.log(1);
resolve('resolve');
}).then(function(data){console.log(data)},function(err){console.log(err)});
//打印出
//1
//resolved
//resolve

这里调用的then方法相当于 Promise.then()的调用

1
2
3
4
5
MyPromise = {
then:function(){...},
status:'',
value:''
}

所以this指向Promise

3.实现异步处理

1)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
function MyPromise(exector) {
var self = this;
self.status = 'pending';
self.value = '';

//存放成功或失败回调数组
self.successCB = [];
self.errorCB = [];

function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved';
self.value = value;
console.log('resolved');
self.successCB.forEach(function(cb){
cb();
})
}
}

function reject(value) {
if (self.status == 'pending') {
self.status = 'rejected';
self.value = value;
console.log('rejected');
self.errorCB.forEach(function(cb){
cb();
})
}
}
exector(resolve, reject);
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
if (this.status == 'resolved') {
onFulfilled(self.value);
}

if (this.status == 'rejected') {
onRejected(self.value);
}

//如果是pending就先存起来函数调用
if (this.status == 'pending') {
this.successCB.push(function () {
onFulfilled(self.value);
})
this.errorCB.push(function () {
onRejected(self.value);
})
}
}

new MyPromise(function (resolve, reject) {
console.log(1);
setTimeout(function () {
resolve('resolve');
}, 2000);
}).then(function (data) { console.log(data) }, function (err) { console.log(err) });
//打印出
//1
//resolved
//resolve

4.实现多个then的链式调用方法

1)

Promise 对象的 then 方法接受两个参数:

1
promise.then(onFulfilled, onRejected)

onFulfilledonRejected 都是可选参数。

  • 如果 onFulfilledonRejected 不是函数,其必须被忽略

onFulfilled 特性

    如果 onFulfilled 是函数:

  • promise 状态变为成功时必须被调用,其第一个参数为 promise 成功状态传入的值( resolve 执行时传入的值)
  • promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

onRejected 特性

    如果 onRejected 是函数:

  • promise 状态变为失败时必须被调用,其第一个参数为 promise 失败状态传入的值( reject 执行时传入的值)
  • promise 状态改变前其不可被调用
  • 其调用次数不可超过一次

多次调用

    then 方法可以被同一个 promise 对象调用多次

  • promise 成功状态时,所有 onFulfilled 需按照其注册顺序依次回调
  • promise 失败状态时,所有 onRejected 需按照其注册顺序依次回调

返回

then 方法必须返回一个新的 promise 对象

2)

如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

  • x 不为 Promise ,则使 x 直接作为新返回的 Promise 对象的值, 即新的onFulfilled 或者 onRejected 函数的参数.
  • xPromise ,这时后一个回调函数,就会等待该 Promise 对象(即 x )的状态发生变化,才会被调用,并且新的 Promise 状态和 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
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
return new MyPromise(function (resolve, reject) {
if (self.status == 'resolved') {
if (typeof onFulfilled == "function") {
//新增部分
let result = onFulfilled(self.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} else {
resolve(self.value);
}
}

if (self.status == 'rejected') {
if (typeof onRejected == "function") {
//新增部分
let result = onRejected(self.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
reject(result);
}
} else {
reject(self.value);
}
}

if (self.status == 'pending') {
self.successCB.push(function () {
if (typeof onFulfilled == "function") {
//新增部分
let result = onFulfilled(self.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} else {
resolve(self.value);
}
})
self.errorCB.push(function () {
if (typeof onRejected == "function") {
//新增部分
let result = onRejected(self.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
reject(result);
}
} else {
reject(self.value);
}
})
}
})
}

抽出一下重复部分,修改了部分,增加了catch方法

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

function MyPromise(exector){
const _that = this;
_that.state = 'pending';
_that.value = '';
_that.successCb = [];
_that.errorCb = [];

const resolve = (data) => {
if(_that.state === 'pending'){
const run = () => {
const runFulfilled = (data) => {
let cb;
while(cb = _that.successCb.shift()){
cb(data);
}
}

const runRejected = (data) => {
_that.state = 'rejected';
_that.value = data;
let cb;
while(cb = _that.errorCb.shift()){
cb(data);
}
}

if(data instanceof MyPromise){
data.then(data=>{
_that.state = 'resolved';
_that.value = data;
runFulfilled(data)
},err=>{
_that.state = 'rejected';
_that.value = data;
runRejected(data)
})
}else{
_that.state = 'resolved';
_that.value = data;
runFulfilled(data);
}
}

setTimeout(run);
}
}

const reject = (data) => {
if(_that.state === 'pending'){
const run = () => {
_that.state = 'rejected';
_that.value = data;
let cb;
while(cb = _that.errorCb.shift()){
cb(data);
}
}
setTimeout(run);
}
}
try{
exector(resolve,reject);
}catch(e){
reject(e);
}
}

MyPromise.prototype.then = function(onFulfilled,onRejected){
const _that = this;
return new MyPromise((resolve,reject)=>{
const onfulfilled = ()=> {
if(typeof onFulfilled === 'function'){
try{
let result = onFulfilled(_that.value);
if(result instanceof MyPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
}catch(e){
reject(e);
}
}else{
resolve(_that.value);
}
}

const onrejected = ()=> {
if(typeof onRejected === 'function'){
try{
let result = onRejected(_that.value);
if(result instanceof MyPromise){
result.then(resolve,reject);
}else{
reject(result);
}
}catch(e){
reject(e);
}
}else{
reject(_that.value);
}
}

if(_that.state === 'pending'){
_that.successCb.push(()=>{
onfulfilled()
})
_that.errorCb.push(()=>{
onrejected()
})
}

if(_that.state === 'resolved'){
try{
onfulfilled();
}catch(e){
onRejected(e);
}
}

if(_that.state === 'rejected'){
try{
onrejected();
}catch(e){
onRejected(e);
}
}

})
}

MyPromise.prototype.catch = function(onRejected){
this.then(undefined,onRejected);
}

MyPromise.all = function(arr){
return new MyPromise((resolve,rejected) => {
let count = 0;
let values = [];
for(let [i,p] of arr.entries()){
MyPromise.resolve(p).then(res=>{
count++;
values[i] = res;
if(count === arr.length){
resolve(values);
}
},err => {
reject(err);
})
}
})
}

MyPromise.resolve = function(value){
if(value instanceof MyPromise)return value;
return new MyPromise(resolve=>resolve(value));

}

MyPromise.reject = function(value){
return new MyPromise((resolve ,reject) => reject(value))
}