JavaScript學習筆記(十三)——生成器(generator)

在學習廖雪峯前輩的JavaScript教程中,遇到了一些須要注意的點,所以做爲學習筆記列出來,提醒本身注意!ajax

若是你們有須要,歡迎訪問前輩的博客https://www.liaoxuefeng.com/學習。異步


generator(生成器)是ES6標準引入的新的數據類型。一個generator看上去像一個函數,但能夠返回屢次。
函數

咱們先看一下函數的概念:學習

一個函數是一段完整的代碼,調用一個函數就是傳入參數,而後返回結果。測試

function foo(x) {
    return x + x;
}

var r = foo(1); // 調用foo函數

在函數執行過程當中,若是沒有遇到 return 語句,控制權沒法交回被調用的代碼。(函數末尾若是沒有return,就是隱含的return undefined;網站

generator定義

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

generator與函數的區別

generator由 function* 定義(注意多出的*號),而且,除了 return 語句,還能夠用 yield 返回屢次this

舉個例子就容易理解了:url

著名的斐波拉切數列,它是由0,1開頭:spa

0 1 1 2 3 5 8 13 21 34 ...

要編寫一個產生斐波那契數列的函數,能夠這麼寫:code

function fib(max) {
    var
        t,
        a = 0,
        b = 1,
        arr = [0, 1];
    while (arr.length < max) {
        [a, b] = [b, a + b];
        arr.push(b);
    }
    return arr;
}

// 測試:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

函數只能返回一次,因此必須返回一個Array

可是,若是換成generator,就能夠一次返回一個數,不斷返回屢次。用generator改寫以下:

'use strict'
function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}

直接調用:

fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}

咱們發現,直接調用一個generator和調用函數不同, fib(5) 僅僅是建立了一個generator對象,尚未去執行它。

調用generator對象有兩個方法:

一是不斷地調用generator對象的 next() 方法:

var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}

 next() 方法會執行generator的代碼,而後,每次遇到 yield x; 就返回一個對象 {value: x, done: true/false} ,而後「暫停」。返回的 value 就是 yield 的返回值, done 表示這個generator是否已經執行結束了。若是 done 爲 true ,則 value 就是 return 的返回值。

當執行到 done 爲 true 時,這個generator對象就已經所有執行完畢,不要再繼續調用 next() 了。

二是直接用 for......of 循環迭代generator對象,這種方式不須要咱們本身加判斷 done :

for (var x of fib(10)) {
console.log(x); // 依次輸出0, 1, 1, 2, 3, ...
}

generator優勢

1.正是因爲generator在執行過程當中能屢次返回,因此它看上去像一個能夠記住執行狀態的函數,利用這一點,能夠經過寫一個generator來實現須要用面向對象才能實現的功能。

好比,用一個對象來保存狀態,咱們通常是用對象的屬性來保存。這樣很繁瑣:

var fib = {
    a: 0,
    b: 1,
    n: 0,
    max: 5,
    next: function () {
        var
            r = this.a,
            t = this.a + this.b;
        this.a = this.b;
        this.b = t;
        if (this.n < this.max) {
            this.n ++;
            return r;
        } else {
            return undefined;
        }
    }
};

2.generator還有另外一個巨大的好處,就是把異步回調代碼變成「同步」代碼。

沒有generator時,用AJAX時須要這麼寫代碼:

ajax('http://url-1', data1, function (err, result) {
    if (err) {
        return handle(err);
    }
    ajax('http://url-2', data2, function (err, result) {
        if (err) {
            return handle(err);
        }
        ajax('http://url-3', data3, function (err, result) {
            if (err) {
                return handle(err);
            }
            return success(result);
        });
    });
});

回調越多,代碼越難看。

經過使用generator時,能夠這麼寫:

try {
    r1 = yield ajax('http://url-1', data1);
    r2 = yield ajax('http://url-2', data2);
    r3 = yield ajax('http://url-3', data3);
    success(r3);
}
catch (err) {
    handle(err);
}

看上去是同步的代碼,其實是異步的代碼。

相關文章
相關標籤/搜索