# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://easonwang.gitbook.io/web_advance/es6-es7-es8/es6_generator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
