ES6 Generator
ES6 Generator
function接上*即是
開啟REPL
function* Fruit() {
yield 'apple';
yield 'banana';
return 'ending';
}
var a = Fruit();執行
a.next()另外試試
Fruit().next()發現如直接對函式下next指令會無法往下遍歷
如沒加上yield
function* f() {
console.log('執行!');
console.log('執行!');
console.log('執行!');
}
var a = f()執行
a.next()發現函式一次執行完畢
yield不可放在沒有*的function中
(function (){
yield 1;
})()執行會錯誤
generator函式執行時不會改變內部變數的值(yield應該放在每行的前面)
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(10);執行
a.next();發現到第二次z即不知道y的值
所以要改成
b.next()
a.next(22/3)
a.next(10+(22/3)+22)雖然要手動指定參數,但我們一般在函式內需要使用依賴變數不會用generator
如何讀取上次yield的變數?
function* foo(x) {
yield y = 2 * ( x + 1);
yield z = (y / 3);
return (x + y + z);
}
var a = foo(10);a.next();//執行三次發現順利計算
但y跟z變全域,因為yield後接var會出錯,而javascript預設也是在function執行完後釋放區域變數,所以本來的設定是yield後如果要變數保存,就必須設他為全域
yield var y = 2 * ( x + 1);使用for of
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}for (let v of foo()) {
console.log(v);
}執行for of後發現chrome告知只有在strict才可執行
如何在chrome dev 加入strict mode?
(function() { "use strict";
//放入你要執行的東西
}());所以我們改成
(function() { "use strict";
for (let v of foo()) {
console.log(v);
}
}());即可順利遍歷*foo()
yield*
在generator函式中插入另一個generator函式時 用到
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
foo();
yield 'y';
}
for (let v of bar()){
console.log(v);
}印出x,y
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
for (let v of bar()){
console.log(v);
}印出x,a,b,y
yield*類似for of
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
for(let v of foo()){
console.log(v);
};
yield 'y';
}
for (let v of bar()){
console.log(v);
}處理callback
原本
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});使用generator
function* longRunningTask() {
try {
var value1 = yield step1();
var value2 = yield step2(value1);
var value3 = yield step3(value2);
var value4 = yield step4(value3);
// Do something with value4
} catch (e) {
// Handle any error from step1 through step4
}
}為任意對象加入Iterator後即可用next()
var arry = ["a","b"]var hi = arry[Symbol.iterator](); //S記得大寫hi.next();測試一個物件對象
var car = {type:"sport", model:"500", color:"white"};接著輸入
for(v of car){console.log(v)}發現物件對象無法用for of遍歷
於是我們再輸入,幫他加入iterator
car[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};這時輸入
for(v of car){console.log(v)}以及
[...car]均可
但輸入next還是不行
car.next()所以我們生成一個b
var b = car[Symbol.iterator]()之輸入b.next(),即可順利印出
b.next()
Object {value: 1, done: false}
b.next()
Object {value: 2, done: false}
b.next()
Object {value: 3, done: false}但如果改成
var b = car[Symbol.iterator]之後輸入
b().next()
Object {value: 1, done: false}
b().next()
Object {value: 1, done: false}
b().next()
Object {value: 1, done: false}發現第一個完後即無法在往下
查看一個數組有沒有iterator
Set.prototype[Symbol.iterator]
Array.prototype[Symbol.iterator]
Map.prototype[Symbol.iterator]
Object.prototype[Symbol.iterator]有[Symbol.iterator]的方法都可用[...名字]去遍歷
只有object無法
yield 實用方法
在Promise中我們會在async function call的完成狀態(onSuccess)調用resolve(要傳下去的值),而在Generator中我們會調用g.next(要傳下去的值);其中next裡面放的是接下來要繼續處理的值
var g = gen(); // 建立函數物件
g.next(); // 開始執行到第一個 yield
var totalDelay = 0;
function delay(ms) {
setTimeout(function() {
console.log("delay "+ms+" ms");
totalDelay += ms;
g.next(totalDelay); // 這個 yield 完成後,傳回 totalDelay 並呼叫 next() 繼續執行到下一個 yield
}, ms);
}
function *gen(){
var a = 5, b = 3, t;
t = yield delay(800);
console.log("a=%d t=%d", a, t);
t = yield delay(500);
b = a + b;
console.log("b = %d t = %d", b, t);
t = yield delay(300);
console.log("totalDelay = %d t=%d", totalDelay, t);
}可參考http://programmermagazine.github.io/mag/pmag201505/focus3.html
Last updated
Was this helpful?