《你不知道的javascript》读书笔记—生成器
生成器函数
生成器函数是一个特殊的函数, 它依旧是一个函数,基本的函数特性都是没有改变的。展示生成器的执行模式
1 | function *foo(x) { |
迭代器
概念
可迭代:迭代器对象,可用的方法:Symbol.iterator
调用next()接收到done:true停止
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
56var something = (function(){
var nextVal ;
return {
[Symbol.iterator]:function(){
return this;
},
next:function(){
if(nextVal === undefined){
nextVal = 1;
}
else{
nextVal = 3*nextVal +6;
}
return {done:false,value:nextVal};
}
};
})();
something.next().value;//1
something.next().value;//9
//遍历迭代器对象
for (var v of something) {//something是一个迭代器对象,迭代器对象可用for...of..去循环
console.log( v );//1 9 33
// 不要死循环!
if (v > 100) {
break;
}
}
//数组用迭代器遍历
var a = [1,3,5,7,9];
for (var v of a) {
console.log( v );
}// 1 3 5 7 9
或者
var a = [1,3,5,7,9];
var it = a[Symbol.iterator]();
it.next().value; // 1
//生成器迭代器
function *something() {
var nextVal;
while (true) {
if (nextVal === undefined) {
nextVal = 1;
} else {
nextVal = (3 * nextVal) + 6;
}
yield nextVal;
}
}
//迭代器遍历
for(var v of something()){//something()是指生成器函数执行就生成了迭代器
console.log(v);
if(v>100){
break
}
}
异步迭代生成器
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//同步实现异步处理方式
function foo(x,y) {
ajax("http://some.url.1/?x=" + x + "&y=" + y,
function(err,data){
if (err) {
// 向*main()抛出一个错误
it.throw( err );
}else {
// 用收到的data恢复*main()
it.next( data );
}
});
}
function *main() {
try {
var text = yield foo( 11, 31 );//由于foo()函数没有返回值,第一个next()返回的是undefined
console.log( text );
}catch (err) {
console.error( err );
}
}
var it = main();
// 这里启动!
it.next();
//生成器+Promise
function foo(x,y) {
return request(
"http://some.url.1/?x=" + x + "&y=" + y
);
}
function *main() {
try {
var text = yield foo( 11, 31 );
console.log( text );
}catch (err) {
console.error( err );}
}
}
var it = main();
var p = it.next().value;//foo()函数返回的值
// 等待promise p决议
p.then(
function(text){
it.next( text );
},
function(err){
it.throw( err );
}
);
//promise驱动的生成器 ==>替代上面生成器+Promise的工具=>一套生成promise的生成器
function run(gen) {
var args = [].slice.call( arguments, 1), it;
// 在当前上下文中初始化生成器
it = gen.apply( this, args );
// 返回一个promise用于生成器完成
return Promise.resolve()
.then( function handleNext(value){
// 对下一个yield出的值运行
var next = it.next( value );
return (function handleResult(next){
// 生成器运行完毕了吗?
if (next.done) {
return next.value;
}
// 否则继续运行
else {
return Promise.resolve( next.value )
.then(
// 成功就恢复异步循环, 把决议的值发回生成器
handleNext,
// 如果value是被拒绝的 promise,
// 就把错误传回生成器进行出错处理
function handleErr(err) {
return Promise.resolve(
it.throw( err )
).then( handleResult );
});
}
})(next);
} );
}
run(main);生成器委托
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//场景:异步请求并发 采用了yield *机制
function *foo() {
var r2 = yield request( "http://some.url.2" );
var r3 = yield request( "http://some.url.3/?v=" + r2 );
return r3;
}
function *bar() {
var r1 = yield request( "http://some.url.1" );
// 通过 yeild* "委托"给*foo()
var r3 = yield *foo();//foo()执行得到生成器
console.log( r3 );
}
run( bar );
//递归委托
function *foo(val) {
if (val > 1) {
// 生成器递归
val = yield *foo( val - 1 );
}
return yield request( "http://some.url/?v=" + val );
}
function *bar() {
var r1 = yield *foo( 3 );
console.log( r1 );
}
run( bar );
生成器并发
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//异步请求并发协调
// request(..)是一个支持Promise的Ajax工具
var res = [];
function *reqData(url) {
var data = yield request( url );
// 控制转移
yield;
res.push( data );
}
var it1 = reqData( "http://some.url.1" );
var it2 = reqData( "http://some.url.2" );
var p1 = it.next();
var p2 = it.next();
p1.then( function(data){
it1.next( data );
} );
p2.then( function(data){
it2.next( data );
} );
Promise.all( [p1,p2] )
.then( function(){
it1.next();
it2.next();
} );
//==>改进方案
// request(..)是一个支持Promise的Ajax工具
runAll(
function*(data){
data.res = [];
// 控制转移(以及消息传递)
var url1 = yield "http://some.url.2";
var p1 = request( url1 ); // "http://some.url.1"
// 控制转移
yield;
data.res.push( yield p1 );
},
function*(data){
// 控制转移(以及消息传递)
var url2 = yield "http://some.url.1";
var p2 = request( url2 ); // "http://some.url.2"
// 控制转移
yield;
data.res.push( yield p2 );
}
);
Thunk.js
1 | //thunkify(..) 的实现接收 foo(..) 函数引用以及它需要的任意参数, 并返回 thunk 本身(fooThunk(..) ) |
ES6之前的生成器
1 | // request(..)是一个支持Promise的Ajax工具 |
本文由 Abert 创作,采用 知识共享署名 4.0 国际许可协议。
本站文章除注明转载/出处外,均为本站原创或翻译,转载请务必署名。