ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
#### 打破函数的完整运行 ``` var x = 1; function *foo() { x++; yield; console.log("x:" + x); } function bar() { x++; } //foo()并不会立即执行函数,而仅仅是构造了一个生成器 var it = foo(); //只有.next()才会真正执行函数,直到遇见yield暂停 it.next(); x; //2 bar(); it.next(); //x:3 ``` next()会返回一个对象 ``` function *foo() { var x = 0; yield; x++; yield; return x; } var it = foo(); it.next(); //{value: undefined, done: false} it.next(); //{value: undefined, done: false} it.next(); //{value: 1, done: true} ``` next也可以接收参数,作为yield的返回值 ``` //注意yield的关键字,加上括号以区分变量 function *foo(x) { var y = x * (yield); return y; } var it = foo(6); it.next(); var res = it.next(7); res.value; //42 ``` next可以将消息传递给yield,同样的,yield也可以给next传递消息 ``` function *foo() { var y = x * (yield "hello"); return y; } var it = foo(6); var res = it.next(); res.value; //hello it.next(7).value; //42 ``` it.return(arg)终止生成器(done:true),arg将作为最终的value值。 #### 异步请求 ``` function foo(x, y) { ajax(url, data, (err, data) => if(err) it.throw(err); else it.next(data)); } function *main() { var text = yield foo(2, 3); console.log(text); } var it = main(); it.next(); //qinchuan(from server) ``` 想想上述代码的逻辑:it.next()启动这个生成器,走到yield foo(2, 3)时暂停,执行foo函数并将函数返回值返回给上一个it.next().value(undefined),相当于yield undefined。而yield在等待下一个next,请求回来后,调用it.next(data),生成器继续执行,data作为yield的返回值返回给text。 如何错误处理? ``` function foo(x, y) { ajax(url, data, (err, data) => if(err) it.throw(err); else it.next(data)); } function *main() { try { var text = yield foo(2, 3); console.log(text); } catch(err) { //it.throw(err)会在这里捕捉到 console.error(err); } } //外部捕获也可以 //清空上述代码 function *main() { var x = yield "hello world"; yield x.toLowerCase(); } var it = main(); it.next(); //value为hello world try { it.next(42); //x为42 执行x.toLowerCase()报错 } catch(err) { console.log(err); //TypeError } ``` #### 生成器+Promise ``` function foo(x, y) { return new Promise((resolve, reject) => { ajax(url + x + y, data => resolve(data), err => reject(err)); }) } function *main() { try { var text = yield foo(2, 3); console.log(text); } catch(err) { console.log(err) } } var it = main(); var ajaxBK = it.next().value; ajaxBK.then(data => it.next(data), err => it.throw(err)); ``` 并发请求 ``` function *foo() { //yield -> res var results = yield Promise.all([request1(), request2()]); var r1 = results[0]; var r2 = results[1]; //yield -> res3 var r3 = yield request3(); console.log(r3); } var it = foo(); var rp12 = it.next().value; rp12.then(res => { var rp3 = it.next(res).value; rp3.then(res3 => it.next(res3);); }); ``` #### 生成器委托 ``` function *foo() { console.log('foo start') yield 3; yield 4; } function *bar() { yield 1; yield 2; yield *foo(); yield 5; console.log('finish') } var it = bar(); it.next().value; //1 it.next().value; //2 it.next().value; //foo start //3 it.next().value; //4 it.next().value; //5 it.next(); //finish ``` 当走到yield *foo()时,自动执行foo().next()启动foo,此时的it变成了foo,foo执行完毕后it又变回bar 看得懂下面的例子,你就懂委托了 ``` function *foo() { console.log("inside *foo()", yield "B"); console.log("inside *foo()", yield "C"); return "D"; } function *bar() { console.log("inside *bar()", yield "A"); console.log("inside *bar()", yield *foo()); console.log("inside *bar()", yield "E"); return "F"; } var it = bar(); console.log("outside:", it.next().value); //outside: A console.log("outside:", it.next(1).value); //inside *bar() 1 //outside: B console.log("outside:", it.next(2).value); //inside *foo() 2 //outside: C console.log("outside:", it.next(3).value); //inside *foo() 3 //inside *bar() D //outside:E console.log("outside:", it.next(4).value); //inside *bar() 4 //outside: F ``` yield委托的不一定必须是另一个生成器,也可以是一个iterable ``` function *bar() { console.log("inside *bar()", yield "A"); console.log("inside *bar()", yield *["B", "C", "D"]); console.log("inside *bar()", yield "E"); return "F"; } var it = bar(); console.log("outside:", it.next().value); //outside: A console.log("outside:", it.next(1).value); //inside *bar() 1 //outside: B console.log("outside:", it.next(2).value); //outside: C console.log("outside:", it.next(3).value); //outside: D console.log("outside:", it.next(4).value); //inside *bar() undefined //outside: E iterable返回的是undefined console.log("outside:", it.next(5).value); //inside *bar() 5 //outside: F ``` 异常也会被委托,但是,如果内层生成器的异常没有在外层捕获处理的话,那么外层生成器将会置为done ``` function *foo() { try { yield "B"; } catch(err) { console.log("error caught inside *foo()", err); } yield "C"; throw "D"; } function *bar() { yield "A"; try { yield *foo(); } catch(err) { console.log("error caught inside *bar()", err); } yield "E"; yield *baz(); yield "G"; } function *baz() { throw "F"; } var it = bar(); console.log("outside:", it.next().value); //outside: A console.log("outside:", it.next(1).value); //outside: B console.log("outside:", it.throw(2).value); //error caught inside *foo() 2 //outside: C console.log("outside:", it.next(3).value); //error caught inside *bar() D //outside: E try { console.log("outside:", it.next(4).value); } catch(err) { console.log("error caught outside:", err); //error caught outside: F } //baz中出现异常,而外部的bar并没有将其捕获,导致异常继续向上传递到最外层被捕获,同时出现异常的baz和外部函数bar均进入到了done阶段,G永远不会走到。 ``` #### 生成器并发 ``` //request是promise类型的ajax var res = []; function *reqData(url) { var data = yield request(url); yield; res.push(data); } var it1 = reqData(url1); var it2 = reqData(url2); var p1 = it1.next().value; var p2 = it2.next().value; p1.then(res1 => it1.next(res1)); p2.then(res2 => it2.next(res2)); Promise.all([p1, p2]).then(() => {it1.next(); it2.next();}) ``` #### 形实转换工具(thunk) thunk:一个用于调用另一个函数的函数,自身没有参数 ``` function foo(x, y) { return x + y; } function fooThunk() { return foo(3, 4); } fooThunk(); //7 //异步thunk,可以有回调 function foo(x, y, cb) { setTimeout(() => cb(x + y), 1000); } function fooThunk(cb) { foo(3, 4, cb); } fooThunk(sum => console.log(sum);); //7 ``` 封装 ``` function thunkify(fn) { var args = [].slice.call(arguments, 1); // -> [3, 4], 如果没有那个1的话将会是[fn, 3, 4] return function(cb) { args.push(cb); // -> [3, 4, (sum) => console.log(sum)] return fn.apply(null, args); } } var fooThunk = thunkify(foo, 3, 4); fooThunk(sum => console.log(sum)); //7 function thunkify(fn) { return function() { var args = [].slice.call(arguments); return function(cb) { args.push(cb); return fn.apply(null, args); } } } var fooThunkory = thunkify(foo); var fooThunk1 = fooThunkory(3, 4); var fooThunk2 = fooThunkory(5, 6); fooThunk1(sum => console.log(sum)); //7 fooThunk2(sum => console.log(sum)); //11 ``` #### 手动实现生成器 p280页,掌握其原理