#### 打破函数的完整运行
```
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页,掌握其原理
- 你不知道的JS上
- 第一部分 第三章 函数作用域和块作用域
- 第一部分 第四章 提升
- 第一部分 第五章 闭包
- 第二部分 第一章 关于this
- 第二部分 第二章 this全面解析
- 第二部分 第三章 对象
- 第二部分 第五章 原型
- 第二部分 第六章 行为委托
- 你不知道的JS中
- 第一部分 第二章 值
- 第一部分 第三章 原生函数
- 第一部分 第四章 强制类型转换
- 第一部分 第五章 语法
- 第二部分 第一章 异步
- 第二部分 第三章 Promise
- 第二部分 第四章 生成器
- 第二部分 第五章 性能
- 你不知道的JS下
- 第一部分 总结
- 第二部分 第二章 语法
- 第二部分 第三章 代码组织
- 第二部分 第四章 Promise
- 第二部分 第五章 集合
- 第二部分 第六章 新增API
- 第二部分 第七章 元编程
- 第二部分 第八章 ES6之后