首頁  >  文章  >  web前端  >  JavaScript中Generator函數的詳理解

JavaScript中Generator函數的詳理解

不言
不言轉載
2019-03-20 10:26:502067瀏覽

這篇文章帶給大家的內容是關於JavaScript中Generator函數的詳理解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

這篇是關於ES6中生成器函數相關總結與理解...

Generator函數的定義

在阮一峰老師的書中的敘述是:  
Generator 函數有多種理解角度。語法上,首先可以把它理解成,Generator 函數是一個狀態機,封裝了多個內部狀態。執行 Generator 函數會傳回一個遍歷器物件,也就是說,Generator 函數除了狀態機,還是一個遍歷器物件產生函數。傳回的遍歷器對象,可以依序遍歷 Generator 函數內部的每一個狀態。

我的理解:  
產生器函數可以理解為: 函數內部是由多個小函數組成的, 使用yield關鍵字將函數內部分割成多個區塊區域; 並且當函數執行時, 遇到yield就會停止, 並且將yield 後面的表達式結果輸出(當然外部要調用next()方法); 下次再調用next()方法時, 就從上一個停止的地方開始執行(這意味著函數有有記憶功能); 如果下面沒有再遇到yield的話就像普通函數執行完. 函數的返回值是一個可迭代對象(遍歷器對象); 我喜歡叫可迭代對象, 或者說可遍歷對象...

說一說可迭代物件(iterator)的next()方法

function CreateIterator(iterator) {
    // 定义一个初始下标用来判断
    let nextIndex = 0;

    // 返回对象: 包含的next方法, 
    return {
        next: function () {
            // 返回一个对象: value是当前对象下标对应的值, done是是否遍历完成
            return nextIndex <p style="white-space: normal;"><strong>生成器函數的使用</strong></p><pre class="brush:php;toolbar:false">generator生成器函数的使用:
function *fn() {
    代码1; 
    yield; 
    代码2;
}
普通函数: 执行到底
生成器函数: 遇到yield会暂停,交出执行权,下次执行从上次的停止的位置继续
生成器函数返回值为: 生成器对象
生成器对象.next()方法才能执行 函数体中的代码
// 可以解决函数回调嵌套的问题; 解决耗时操作
function *func() {
    // 请求数据.
    // yield ajax() 
    // 处理数据
} 
// generator函数本质上 分割成多个小函数来执行... yield关键字前后
// 遇到yield就暂停; 没有就往下执行...
// yield 起到了 暂停函数执行的作用

關於yield關鍵字的理解

yield傳值

JavaScript中Generator函數的詳理解

#yield輸出值

JavaScript中Generator函數的詳理解

舉個栗子:

     function *g2(x, y) {        
    let sum = x+y;
    yield sum; // sum是第一个输出结果
        
    let agv = sum / 2;
    yield agv; // agv 是第二个输出的结果
    
    return {"和": sum, "平均数": agv}; // 最后一个结果
}
    
let gg2 = g2(100, 20);        
console.log(gg2.next().value);  // 120
console.log(gg2.next().value);  // 60
console.log(gg2.next().value);  // { '和': 120, '平均数': 60 }

Generator的應用

這裡只做一個簡單舉例, 像我們平常使用的ES7中的async 函數; 他就是生成器函數的一種應用; 它其實是Generator 函數的語法糖。

借用ES6入門中的一個例子: 兩種方式去讀取檔案

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

// 1.使用生成器函数 读取文件
const gen = function* () {
  const f1 = yield readFile(__dirname + '/first.json');
  const f2 = yield readFile(__dirname + '/second.json');

  console.log(f1.toString());  // 没有输出; 因为 f1 拿到是一个 Iterator 对象 
  console.log(f2.toString());
};

// 使用 async + await 读取; 注意两种需配合使用
const asyncReadFile = async function () {
    const f1 = await readFile(__dirname + '/first.json');
    const f2 = await readFile(__dirname + '/second.json');

    console.log(f1.toString());  //async函数的返回值是 Promise 对象
    console.log(f2.toString());
};

gen(); // 没有值, 需要用 next()方法去取值
asyncReadFile() // 返回值 {"hello": "first"} {"hello": "second"}

所以; 我們這裡比較一下; async函數是將Generator 函數的星號(*)替換成async ,將yield替換成await,大大方便了我們的使用。

平常的非同步程式碼我們就可以使用async await的形式來實現...
例如vue中的一個ajax請求去獲取資料

methods: {
    async getApi() {
        let res = await axios.get('url')
        // 这里的执行顺序是同步的...
        console.log(res)
    }
}

這篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的JavaScript教學影片欄位!

#

以上是JavaScript中Generator函數的詳理解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除