手写Promise及其静态方法

Promise.resolve

  • 1、Promise.resolve最终结果还是一个Promise,并且与Promise.resolve(该值)传入的值息息相关
  • 2、传入的参数可以是一个Promise实例,那么该函数执行的结果是直接将实例返回
  • 3、这里最主要需要理解跟随,可以理解成Promise最终状态就是这个thenable对象输出的值

源码实现

1
2
3
4
5
6
7
8
9
10
Promise.myResolve = function(value) {
// 是Promise实例,直接返回即可
if (value && value typeof 'object' && (value instanceof Promise)) {
return value
}
// 否则其他情况一律再通过Promise包装一下
return new Promise(resolve => {
resolve(value)
})
}

Promise.reject

Promise.reject() 方法返回一个带有拒绝原因的Promise对象。

源码实现

1
2
3
4
5
Promise.myReject = function(value) {
return new Promise((_, reject) => {
reject(value)
})
}

Promise.all

源码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Promise.myAll = function(promises) {
return new Promise((resolve, reject) => {
const result = []
let count = 0
if (promises.length === 0) {
resolve(result)
}
promises.forEach((item, index) =>{
Promise.resolve(item).then(res => {
count += 1
result[index] = res
if (count === promises.length){
resolve(result)
}
}).catch(err =>{
reject(err)
})
})
})
}

Promise.allSettled

方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更,一旦发生状态变更,状态总是fulfilled,不会变成rejected

  • 不管是全部成功还是有部分失败,最终都会进入Promise.allSettled的.then回调中
  • 最后的返回值中,成功和失败的项都有status属性,成功时值是fulfilled,失败时是rejected
  • 最后的返回值中,成功含有value属性,而失败则是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
Promise.prototype.myAllSettled = function(promises) {
return new Promise((resolve, reject) => {
const result = []
let count = 0
if (promises.length === 0) {
resolve(result)
}
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
count += 1
result[index] = {
status: 'fulfilled',
value: res
}
if (count === promises.length) {
resolve(result)
}
}).catch(err => {
count += 1
result[index] = {
status: 'rejected',
reason: err
}
if (count === promises.length) {
resolve(result)
}
})
})
})
}

Promise.race

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

1
const p = Promise.race([p1, p2, p3])

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
源码实现

1
2
3
4
5
6
7
Promise.myRace = (promises) => {
return new Promise((resolve, reject) => {
promises.forEach(item => {
Promise.resolve(item).then(resolve).catch(reject)
})
})
}

手写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
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
class Promise {
constructor(executor) {
this.state = 'pending'
this.value = 'undefined'
this.reason = 'undefined'
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []

let resolve = value => {
this.state = 'fulfilled'
this.value = value
this.onResolvedCallbacks.forEach(fn => fn())
}

let reject = reason => {
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}

try {
executor(resolve, reject)
} catch(error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolve(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
}

if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
}

if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
})

this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2,x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
}



function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return new TypeError('chaining cycle detected for promise')
}
let called
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, err => {
if (called) return
called = true
reject(err)
})
}
} catch(error) {
if (called) return
called = true
reject(error)
}
} else {
resolve(x)
}
}

// resolve
Promise.resolve = function(value) {
if (value && typeof value === 'object' && (value instanceof Promise)) {
return value
}
return new Promise(resolve => {
resolve(value)
})
}

// reject
Promise.reject = function(value) {
return new Promise((_, reject) => {
reject(value)
})
}

// all
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
let result = []
let count = 0
let len = promises.length
if (len === 0) {
resolve([])
}
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
count += 1
result[index] = res
if (count === len) {
resolve(result)
}
}).catch(err => {
reject(err)
})
})
})
}

// allSettled
Promise.allSettled = function(promises) {
return new Promise((resolve, reject) => {
let result = []
let count = 0
let len = promises.length
if (len === 0) {
resolve([])
}
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
count += 1
result[index] = {
status: 'fulfiled',
value: res
}
if (len === count) {
resolve(result)
}
}).catch(err => {
count += 1
result[index] = {
status: 'rejected',
reason: err
}
if (len === count) {
resolve(result)
}
})
})
})
}

// race
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach(item => {
Promise.resolve(item).then(resolve).catch(reject)
})
})
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!