-
Notifications
You must be signed in to change notification settings - Fork 0
/
co.js
78 lines (67 loc) · 1.92 KB
/
co.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
/**
* tj 大神 co 模块的伪实现
* https://github.com/tj/co
*
* 用于 Generator 函数的自动执行 (流程管理)
* 受 redux-saga [ˈsägə] 启发
*/
/* ---- 使用 next(value) 作为 yield 返回 ---- */
function requestAsync() {
console.log('start request');
new Promise(res => setTimeout(res, 2000, Math.random())).then(result => g.next(result));
}
function* gen() {
console.log('start gen');
const result = yield requestAsync();
console.log(result);
}
// 准备好 g 此时 gen 内部并未执行
const g = gen();
/**
* 0. --> g.next().done === false
* 1. --> console.log('start gen')
* 2. --> yield requestAsync() && PAUSE!!!
* 3. --> requestAsync 内部 Promise resolve 后 result => g.next(result)
* 4. --> gen 内部继续执行 && (yield requestAsync()) => result && console.log(result)
* 5. --> g.next(result).done === true
*/
g.next();
/* ---- co 伪实现 ---- */
/**
* @param {function*} gen
*
* 0. --> gen() => g
* 1. --> g.next(res: undefined) --> (yield new Promise...)
* 2. --> ret = g.next(res: undefined) => ret.value: Promise<val>
* 2. --> ret.value.then(onFulfilled) => onFulfilled(val)
* 3. --> g.next(val) --> (yield new Promise...) => val
* 4. --> const res = val ...
* 5. --> yield ...
*/
function co(gen) {
return new Promise((resolve, reject) => {
const g = gen();
onFulfilled();
function onFulfilled(res) {
let ret;
try {
ret = g.next(res);
} catch (e) {
return reject(e);
}
next(ret);
}
function next(ret) {
if (ret.done) return resolve(ret.value);
return ret.value.then(onFulfilled);
}
});
}
co(function*() {
const res1 = yield new Promise(res => setTimeout(res, 2500, 10));
console.log(res1);
const res2 = yield new Promise(res => setTimeout(res, 500, res1 + 10));
console.log(res2);
const res3 = yield new Promise(res => setTimeout(res, 500, res2 + 10));
console.log(res3);
});