-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
318 lines (294 loc) · 8.94 KB
/
index.js
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
"use strict";
var immediate = require('immediate')
var validStates = {
PENDING: 0,
FULFILLED: 1,
REJECTED: 2
}
var Utils = {
isFunction: function (val) {
return val && typeof val === "function";
},
isObject: function (obj) {
return obj && typeof obj === "object";
},
isPromise: function (val) {
return val && val.constructor === KPromise;
},
isValidState: function(state) {
return (
(state === validStates.PENDING) ||
(state === validStates.REJECTED) ||
(state === validStates.FULFILLED))
},
runAsync: function (func) {
immediate(func)
}
}
/**
* 对 promise 的状态进行改变的函数,改变后会自动检测状态并执行
*
* @param {Promise} promise 需要改变状态的 promise
* @param {State} state 变更为该状态
* @param {Promise|Thenable|value} value resolve 的 value, reject 的 reason
* @return {} 不符合变更状态的条件是直接停止运行
*/
var transition = function (promise, state, value) {
if (
promise.state === state ||
arguments.length !== 3 ||
!Utils.isValidState(state) ||
promise.state !== validStates.PENDING) {
return ;
}
promise.state = state;
promise.value = value;
// 每一次改变状态后执行一次 runner 函数
runner(promise);
}
/**
* 检测当前状态,如果不为 PENDING,则根据状态不同调用事先注册的函数
* 所有的 then 方法中注册的函数均在此处执行
*
* @param {Promise} promise 要执行的 promise
* @return {} 无返回值
*/
var runner = function (promise) {
var promise1 = promise;
if (promise1.state === validStates.PENDING) {
return ;
}
// 根据规范: onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用
// 此处使用工具中的 runAsync 实现
Utils.runAsync(function () {
while(promise1.queue.length) {
var promise2 = promise1.queue.shift(),
handler = null,
value
// 根据设置的状态调用对应的函数
if (promise1.state === validStates.FULFILLED) {
// 根据规范:如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
// 此时 promise1 已经成功执行,如果 promise2 的 onFulfilled 不是函数,我们则直接使用该默认函数,返回相同值
handler = Utils.isFunction(promise2.onFulfilled) ?
promise2.onFulfilled :
function(v) { return v };
} else if (promise1.state === validStates.REJECTED) {
// 根据规范: 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因
// 此时状态为 rejected ,promsie1 已经拒绝执行,如果 promise2 的 onRejected 不是函数,则直接使用相同原因拒绝执行
handler = Utils.isFunction(promise2.onRejected) ?
promise2.onRejected :
function(e) { throw e };
}
// 根据规范: 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
try {
// 根据规范: onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)
value = handler(promise1.value)
} catch(e) {
// 此时捕捉到执行期的异常,以此 reject promise2
promise2.reject(e)
// 继续运行后续的 promise
continue
}
// 根据规范: 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
// 执行 Resolve 过程
doResolve(promise2, value)
}
})
}
/**
* 核心的 Resolve 函数,需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),
* 如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。
* 这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then 方法即可;
* 这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。
*
* @param {Promise} promise 需要处理的 promise
* @param {Value | Thenable} x resolve 的值
* @return {} 无返回值
*/
var doResolve = function (promise, x) {
if (promise === x) {
var msg = "can't resolve the same Promise"
promise.reject(new TypeError(msg))
}
// 当 resolve 的值 x 也是 promise 的时候
// 当前 promise 的 state 则依赖 x 的 state
else if (Utils.isPromise(x)) {
if (x.state === validStates.PENDING) {
// 在依赖的 promise 后添加 then 方法
// 当其状态改变时,使用该 then 方法 改变当前 promise 状态
x.then(function(val) {
doResolve(promise, val)
}, function(reason) {
promise.reject(reason)
})
} else {
// 当依赖的 promise 不是 PENDING 状态时
// 则直接将其值和状态传递到当前 promise
transition(promise, x.state, x.value)
}
}
// 处理当 x 是对象或函数的情况
else if (Utils.isObject(x) || Utils.isFunction(x)) {
var called = false,
thenHandler
try {
thenHandler = x.then
if (Utils.isFunction(thenHandler)) {
thenHandler.call(x,
function (y) {
if (!called) {
doResolve(promise, y)
called = true
}
},
function(r) {
if (!called) {
promise.reject(r)
called = true
}
}
)
} else {
// then 不是函数 则以 x 为参数执行 promise
promise.resolve(x)
called = true
}
} catch(e) {
// 取 x.then 值或调用 x.then 时抛出异常,
// 则以该异常拒绝 promise
if (!called) {
promise.reject(e)
called = true
}
}
}
// 当 x 不是对象或者函数时,以 x 为参数执行 promise
else {
promise.resolve(x)
}
}
function KPromise (func) {
var that = this;
this.value = undefined;
this.state = validStates.PENDING;
this.queue = [];
if (Utils.isFunction(func)) {
func(function (value) {
doResolve(that, value)
}, function (err) {
that.reject(err)
})
}
};
KPromise.prototype.then = function (onFulfilled, onRejected) {
var promise = new KPromise();
// 每个子 promise 会具有这两个属性
// 代表的是通过 then 方法添加的回调
promise.onFulfilled = onFulfilled;
promise.onRejected = onRejected;
this.queue.push(promise);
runner(this);
return promise;
}
KPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
KPromise.prototype.resolve = function(value) {
transition(this, validStates.FULFILLED, value)
}
KPromise.prototype.reject = function(reason) {
transition(this, validStates.REJECTED, reason)
}
// 其它静态方法
/**
* Promise.all() 方法指当数组中的所有 promises 已完成,或者第一个传递的 promise(指 reject)失败时,返回 promise。
* @param {Array[KPromise]} arr 要执行的 promise 数组
* @return {KPromise} 返回一个
*
* var p1 = KPromise.resolve(3);
* var p2 = 1337;
* var p3 = new KPromise((resolve, reject) => {
* setTimeout(resolve, 100, "foo");
* });
*
* KPromise.all([p1, p2, p3]).then(values => {
* console.log(values); // [3, 1337, "foo"]
* });
*/
KPromise.all = function(arr) {
var p = new KPromise(),
results = [],
counter = 0
arr.forEach(function(v, k) {
if (Utils.isPromise(v)) {
v.then(function(data) {
results[k] = data
counter++
if (counter >= arr.length) p.resolve(results)
}).catch(function(err) {
p.reject(err)
})
} else {
results[k] = v
counter++
if (counter >= arr.length) p.resolve(results)
}
})
return p
}
/**
* Promise.race() 方法返回一个 promise,在可迭代的 resolves 或 rejects 中 promises 有一个完成或失败,将显示其值或原因。
* @param {Array[KPromise]} arr promise 数组
* @return {KPromise} 返回一个新 promise
*/
KPromise.race = function(arr) {
var p = new KPromise()
arr.forEach(function(promise, key) {
if (Utils.isPromise(promise)) {
promise.then(function(value) {
p.resolve(value)
}, function(reason) {
p.reject(reason)
})
}
})
return p
}
/**
* 返回一个直接 resolve 的 promise
* @param {Any} data 可以传入一个数据或一个 thenable 对象
* @return {KPromise} 返回一个 promise
*/
KPromise.resolve = function(data) {
return new KPromise(function(resolve) {
resolve(data)
})
}
KPromise.reject = function(reason) {
return new KPromise(function(resolve, reject) {
reject(reason)
})
}
module.exports = {
resolved: function (value) {
return new KPromise(function (resolve) {
resolve(value);
});
},
rejected: function (reason) {
return new KPromise(function (resolve, reject) {
reject(reason);
});
},
deferred: function () {
var resolve, reject;
return {
promise: new KPromise(function (rslv, rjct) {
resolve = rslv;
reject = rjct;
}),
resolve: resolve,
reject: reject
};
}
};