#### 打破函數的完整運行
```
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之后