接續上一篇的 iterator,來看看 generators 到底是什麼?
Generator function (function*)
1 | function* name([param[, param[, ... param]]]) { |
一個 generator 函示,使用 function* 作為宣告,會回傳一個 Generator 物件。
generator可以被中斷跳出,等到再次呼叫的時候再繼續執行。
呼叫 function* 並不會立刻執行函式內容,而是會回傳一個 iterator 物件。當執行 iterator 的 next 方法的時候,function* 裡面的 code 才會被執行,並停在第一個 yield expression 前。呼叫 next 並執行,會回傳一個物件,該物件會帶有一個 value 屬性,其值就是 yield 回傳的值,還會帶有一個 done 屬性,他的型態是 boolean。({value: val, done: true/false})。當該 yield expression 是最後一個的時候,done 屬性會是 true。
generator 裡面的 yield expeession 不一定就直接回傳一個值。也可以再指向另一個 generator function。如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
var gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
generators 也可以帶入參數。如下面的範例:
1 | function* logGenerator() { |
當 function* 裡面有 return,在執行到該行的時候該 function* 就會結束。即使後面還有其他的 yield expression,呼叫 next 也不會再繼續執行。
當 generator 執行完,會回傳 {value: undefined, done: true}。
Generators 不能作為建構函式
以下內容整理自這段影片 Generators in JavaScript
用 generator 來改寫 iterator
利用 generator 來改寫上一篇的範例中的 iterator。
1 | const dragonArmy = { |
generator 範例
宣告一個 someDragon 的 generator 函式來觀察 generator 的執行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15funtion* someDragon(){
while(true){ // it's always true
const enoughDragonSpawned = Math.random() > 0.75;
if( enoughDrangonSpawned ) return
yield makeDragon()
}
}
const iterator = someDragons();
iterator.next() // { value: 'medium lightning dragon', done: false }
iterator.next() // { value: 'tiny lightning dragon', done: false }
iterator.next() // { value: 'big fire dragon', done: false }
iterator.next() // { value: 'undefined', done: true }
iterator.next() // { value: 'undefined', done: true }
iterator.next() // { value: 'undefined', done: true }
1 | funtion* someDragon(){ |
再重複一次
Calling a generator function does NOT run it …yet!
iterators 跟 generator 的關係,可以想成電視和遙控器的關係。
iterators 就像是遙控器,透過 next() 來操縱 generator 的執行。
影片的總結說到,
It’s just a SYNTX SUGAR to help create iterator.
generator 就是一個語法糖,可以更容易的建立 iterator。
不使用 generator 來重寫 someDragon 函式
透過下面的重寫,可以更清楚看出來整個流程,也可以比較出為什麼主持人會說 generator 是語法糖。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24function someDragons(){
let iterations = -1;
const iterator = {
next: () => {
iterations ++
if(iterations === 0)
return { value: 'fluffykins dragon', done: false };
if(iterations === 1)
return { value: 'mark the fine dragon', done: false };
if(iterations === 2){
if (Math.random > 0.5){
return {value: 'hardy the dog', done: true}
}
}
return {done: true};
}
}
return iterator
}
const iterator = someDragons();
console.log(iterator.next()) // {value: 'fluffykins dragon', done: false }
console.log(iterator.next()) // {value: 'mark the fine dragon', done: false }
console.log(iterator.next()) // { done: false }
小結
本篇主要是延續上一篇有關 iterators 來介紹 generators,至於有關 async 是怎麼建立在 generators 上,async, await f又是怎麼一回事就等之後再來繼續研究。