generator自动运行器

  目录

手写一个generator自动运行器

generator自动运行器

generator函数是es6新出的功能,之后又推出了async函数,操作异步真的是超级简单。我觉得我们在实际项目中使用generator的机会非常少,即使使用,一般也会依赖co这样的库来方便的使用generator。
但是我却想研究一下generator,所以写了一个generator不用手动的调用next函数,而是自动的调用。

generator手动next代码

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
var p1 = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
});
}
var p2 = function(val) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(val+2);
}, 2000);
});
}
var p3 = function(val) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(val+3);
}, 1500);
});
}
var p1callback = function(res) {
console.log('第1个yield的callback啊->', res);
}
var p2callback = function(res) {
console.log('第2个yield的callback啊->', res);
}
var p3callback = function(res) {
console.log('第3个yield的callback啊->', res);
}

function *gen() {
var val_1 = yield p1();
var val_2 = yield p2(val_1);
var val_3 = yield p3(val_2);
}
var g = gen();
window.gObj = null;
window.gObj_index = 0;
gObj = g.next();
gObj.value.then(function(res) {
console.log('第1个yield的callback啊->', res);
gObj = g.next(res);
gObj.value.then(function(res) {
console.log('第2个yield的callback啊->', res);
gObj = g.next(res);
gObj.value.then(function(res) {
console.log('第3个yield的callback啊->', res);
});
});
});

上面的代码,需要在generator函数里手动定义yield的表达式,之后在执行的时候需要手动的调用next函数,但是可以看出来,还是有嵌套的情况。

generator自动运行代码

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
// p1,p2,p3是3个Promise的执行函数
var p1 = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
});
}
var p2 = function(val) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(val+2);
}, 2000);
});
}
var p3 = function(val) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(val+3);
}, 1500);
});
}
// p1callback,p2callback,p3callback对应着p1,p2,p3的回调
var p1callback = function(res) {
console.log('第1个yield的callback啊->', res);
}
var p2callback = function(res) {
console.log('第2个yield的callback啊->', res);
}
var p3callback = function(res) {
console.log('第3个yield的callback啊->', res);
}
/**
* @desc generator的生成函数
* @param { Array } Promise的函数数组
* @retuen { Function } generator函数
*/
function gen(arr) {
var valArr = [];
return function *() {
for(var i=0; i<arr.length; i++) {
valArr[i] = yield arr[i](valArr[i-1]);
}
}
}
/**
* @desc 自动执行generator的next()的函数
* @param { Function } gen函数
* @param { Array } Promise函数对应的回调函数数组
* @param { Any } 向generator的next中传入的值
*/
function co(gen, arr, res) {
var g = gen();
var gObj = null;
var gObj_index = 0;
function innerCo(g, arr, res) {
gObj = g.next(res);
if(gObj.done) return void 0;
gObj.value.then(function(res) {
arr[gObj_index++](res);
if(!gObj.done) {
innerCo(g, arr, res);
}
});
}
innerCo(g, arr, 0);
}
// 执行co函数
co(gen([p1,p2,p3]), [p1callback, p2callback, p3callback], 0);

可以看出来,最后只需要co(gen([p1,p2,p3]), [p1callback, p2callback, p3callback], 0);这样一行代码,省去了定义yield,省去了调用next。

总结

  • 首先,我并没有去参考co这样的库的使用方法,如何使用都是自己想出来的。
  • 目前代码只是超级简化版,我也是想验证一下我的想法而已,只有resolve的回调,并没写reject的回调。

最后,代码在这里