Promise a+

Promise A+ 规范

  1. promise:是一个拥有then方法的对象或函数,其行为符合本规范。
  2. thenable:是一个定义了then方法的对象或函数。这个主要是用来兼容一些老的Promise实现,只要一个Promise实现是thenable,也就是拥有then方法的,就可以跟Promises/A+
    兼容。
  3. value:指reslove出来的值,可以是任何合法的 JS 值(包括 undefined , thenablepromise等)
  4. exception:异常,在Promise里面用throw抛出来的值
  5. reason:拒绝原因,是reject里面传的参数,表示reject的原因

Promise Status

  1. pending: 一个promiseresolve或者reject前就处于这个状态。
  2. fulfilled: 一个promiseresolve后就处于fulfilled状态,这个状态不能再改变,而且必须拥有一个不可变的值(value)。
  3. rejected: 一个promisereject后就处于rejected状态,这个状态也不能再改变,而且必须拥有一个不可变的拒绝原因(reason)。

thenable

1
promsie.then(onFulfilled, onRejected)

Optional parameters

  1. 如果 onFulfilled 不是函数,其必须被忽略
  2. 如果 onRejected 不是函数,其必须被忽略

onFulfilled

如果 onFulfilled 是函数:

  1. promise 执行结束后其必须被调用,其第一个参数为 promise 的终值value
  2. promise 执行结束前其不可被调用
  3. 其调用次数不可超过一次

onRejected

如果 onRejected 是函数:

  1. promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因reason
  2. promise 被拒绝执行前其不可被调用
  3. 其调用次数不可超过一次

then

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

  1. promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
  2. promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调

Return

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

1
promise2 = promise1.then(onFulfilled, onRejected)
  1. 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行 Promise 解决过程:[[Resolve]](promise2, x)
  2. 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  3. 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  4. 如果 onRejected 不是函数且 promise1 拒绝执行, 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
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
var PENDING = "pending"
var FULFILLED = "fulfilled"
var REJECTED = "rejected"

function Promise(fn) {
this.status = PENDING // initial status
this.value = null // initial value
this.reason = null // initial reason
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []

var _this = this

function resolve(value) {
if (_this.status === PENDING) {
_this.status = FULFILLED
_this.value = value

_this.onFulfilledCallbacks.forEach((i) => i(_this.value))
}
}

function reject(reason) {
if (_this.status === PENDING) {
_this.status = REJECTED
_this.reason = reason

_this.onRejectedCallbacks.forEach((i) => i(_this.reason))
}
}

try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}

function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("The promise and the return value are the same"))
}

if (x instanceof Promise) {
x.then(function (y) {
resolvePromise(promise, y, resolve, reject)
}, reject)
} else if (typeof x === "object" || typeof x === "function") {
if (x === null) {
return resolve(x)
}

try {
var then = x.then
} catch (e) {
return reject(e)
}

if (typeof then === "function") {
var called = false

try {
then.call(
x,
function (y) {
if (called) return
called = true
resolvePromise(promise, y, resolve, reject)
},
function (r) {
if (called) return
called = true
reject(r)
}
)
} catch (e) {
if (called) return

reject(e)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}

Promise.prototype.then = function (onFulfilled, onRejected) {
var checkOnFulfilled = onFulfilled
if (typeof onFulfilled !== "function") {
checkOnFulfilled = function (value) {
return value
}
}

var checkOnRejected = onRejected
if (typeof onRejected !== "function") {
checkOnRejected = function (reason) {
throw reason
}
}

var _this = this

if (this.status === FULFILLED) {
// 如果前面的 promise 抛出异常,后面的必须拒绝执行
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
if (typeof onFulfilled !== "function") {
resolve(_this.value)
} else {
var x = checkOnFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

return promise2
}

if (this.status === REJECTED) {
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
if (typeof onRejected !== "function") {
reject(_this.reason)
} else {
var x = checkOnRejected(_this.reason)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

return promise2
}

if (this.status === PENDING) {
var promise2 = new Promise(function (resolve, reject) {
_this.onFulfilledCallbacks.push(function () {
setTimeout(function () {
try {
if (typeof onFulfilled !== "function") {
resolve(_this.value)
} else {
var x = checkOnFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

_this.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
if (typeof onRejected !== "function") {
reject(_this.reason)
} else {
var x = checkOnRejected(_this.reason)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})
})

return promise2
}
}

Promise.resolve = function (parameter) {
if (parameter instanceof Promise) {
return parameter
}

return new Promise(function (resolve) {
resolve(parameter)
})
}

Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason)
})
}

Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
var count = 0
var result = []
var len = promises.length

if (length === 0) {
return resolve(result)
}

promises.forEach(function (promise, index) {
Promise.resolve(promise).then(
function (value) {
count++
result[index] = value

if (count === len) {
resolve(result)
}
},
function (reason) {
reject(reason)
}
)
})
})
}

Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
var len = promises.length

if (length === 0) {
return resolve()
} else {
for (var i = 0; i < len; i++) {
Promise.resolve(promises[i]).then(
function (value) {
return resolve(value)
},
function (reason) {
return reject(reason)
}
)
}
}
})
}

Promise.catch = function (onRejected) {
this.then(null, onRejected)
}

Promise.finally = function (fn) {
return this.then(
function (value) {
return Promise.resolve(fn()).then(function () {
return value
})
},
function (error) {
return Promise.resolve(fn()).then(function () {
throw error
})
}
)
}

Promise.allSettled = function (promises) {
return new Promise(function (resolve) {
var len = promises.length
var result = []
var count = 0

if (len === 0) {
resolve(result)
} else {
for (let i = 0; i < len; i++) {
;(function (i) {
var current = Promise.resolve(promises[i])

current.then(
function (value) {
count++
result[i] = {
status: "fulfilled",
value,
}

if (count === len) {
return resolve(result)
}
},
function (reason) {
count++
result[i] = {
status: "rejected",
reason,
}

if (count === len) {
return resolve(result)
}
}
)
})(i)
}
}
})
}

// for promises-aplus-tests test
Promise.deferred = function () {
var result = {}
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve
result.reject = reject
})

return result
}

module.exports = Promise