generator

generator


generator(生成器)是ES6標(biāo)準(zhǔn)引入的新的數(shù)據(jù)類(lèi)型识补。一個(gè)generator看上去像一個(gè)函數(shù),但可以返回多次辫红。

ES6定義generator標(biāo)準(zhǔn)的哥們借鑒了Python的generator的概念和語(yǔ)法李请,如果你對(duì)Python的generator很熟悉,那么ES6的generator就是小菜一碟了厉熟。如果你對(duì)Python還不熟,趕快惡補(bǔ)Python教程较幌!揍瑟。

我們先復(fù)習(xí)函數(shù)的概念。一個(gè)函數(shù)是一段完整的代碼乍炉,調(diào)用一個(gè)函數(shù)就是傳入?yún)?shù)绢片,然后返回結(jié)果:

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

var r = foo(1); // 調(diào)用foo函數(shù)

函數(shù)在執(zhí)行過(guò)程中,如果沒(méi)有遇到return語(yǔ)句(函數(shù)末尾如果沒(méi)有return岛琼,就是隱含的return undefined;)底循,控制權(quán)無(wú)法交回被調(diào)用的代碼。

generator跟函數(shù)很像槐瑞,定義如下:

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

generator和函數(shù)不同的是熙涤,generator由function*定義(注意多出的*號(hào)),并且,除了return語(yǔ)句祠挫,還可以用yield返回多次那槽。

大多數(shù)同學(xué)立刻就暈了,generator就是能夠返回多次的“函數(shù)”等舔?返回多次有啥用骚灸?

還是舉個(gè)栗子吧。

我們以一個(gè)著名的斐波那契數(shù)列為例慌植,它由0甚牲,1開(kāi)頭:

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

要編寫(xiě)一個(gè)產(chǎn)生斐波那契數(shù)列的函數(shù),可以這么寫(xiě):

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;
}

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

函數(shù)只能返回一次蝶柿,所以必須返回一個(gè)Array丈钙。但是,如果換成generator只锭,就可以一次返回一個(gè)數(shù)著恩,不斷返回多次。用generator改寫(xiě)如下:

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

直接調(diào)用試試:

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

直接調(diào)用一個(gè)generator和調(diào)用函數(shù)不一樣蜻展,fib(5)僅僅是創(chuàng)建了一個(gè)generator對(duì)象喉誊,還沒(méi)有去執(zhí)行它。

調(diào)用generator對(duì)象有兩個(gè)方法纵顾,一是不斷地調(diào)用generator對(duì)象的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()方法會(huì)執(zhí)行g(shù)enerator的代碼伍茄,然后,每次遇到yield x;就返回一個(gè)對(duì)象{value: x, done: true/false}施逾,然后“暫头蠼茫”。返回的value就是yield的返回值汉额,done表示這個(gè)generator是否已經(jīng)執(zhí)行結(jié)束了曹仗。如果donetrue,則value就是return的返回值蠕搜。

當(dāng)執(zhí)行到donetrue時(shí)怎茫,這個(gè)generator對(duì)象就已經(jīng)全部執(zhí)行完畢,不要再繼續(xù)調(diào)用next()了妓灌。

第二個(gè)方法是直接用for ... of循環(huán)迭代generator對(duì)象轨蛤,這種方式不需要我們自己判斷done

'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;
}
for (var x of fib(10)) {
    console.log(x); // 依次輸出0, 1, 1, 2, 3, ...
}

Run

0
1
1
2
3
5
8
13
21
34

generator和普通函數(shù)相比,有什么用虫埂?

因?yàn)間enerator可以在執(zhí)行過(guò)程中多次返回祥山,所以它看上去就像一個(gè)可以記住執(zhí)行狀態(tài)的函數(shù),利用這一點(diǎn)掉伏,寫(xiě)一個(gè)generator就可以實(shí)現(xiàn)需要用面向?qū)ο蟛拍軐?shí)現(xiàn)的功能缝呕。例如澳窑,用一個(gè)對(duì)象來(lái)保存狀態(tài),得這么寫(xiě):

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;
        }
    }
};

用對(duì)象的屬性來(lái)保存狀態(tài)岳颇,相當(dāng)繁瑣照捡。

generator還有另一個(gè)巨大的好處,就是把異步回調(diào)代碼變成“同步”代碼话侧。這個(gè)好處要等到后面學(xué)了AJAX以后才能體會(huì)到栗精。

沒(méi)有g(shù)enerator之前的黑暗時(shí)代,用AJAX時(shí)需要這么寫(xiě)代碼:

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);
        });
    });
});

回調(diào)越多瞻鹏,代碼越難看悲立。

有了generator的美好時(shí)代,用AJAX時(shí)可以這么寫(xiě):

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);
}

看上去是同步的代碼新博,實(shí)際執(zhí)行是異步的薪夕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赫悄,隨后出現(xiàn)的幾起案子原献,更是在濱河造成了極大的恐慌,老刑警劉巖埂淮,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姑隅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡倔撞,警方通過(guò)查閱死者的電腦和手機(jī)讲仰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)痪蝇,“玉大人鄙陡,你說(shuō)我怎么就攤上這事□飭” “怎么了趁矾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)给僵。 經(jīng)常有香客問(wèn)我愈魏,道長(zhǎng),這世上最難降的妖魔是什么想际? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮溪厘,結(jié)果婚禮上胡本,老公的妹妹穿的比我還像新娘。我一直安慰自己畸悬,他們只是感情好侧甫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般披粟。 火紅的嫁衣襯著肌膚如雪咒锻。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天守屉,我揣著相機(jī)與錄音惑艇,去河邊找鬼。 笑死拇泛,一個(gè)胖子當(dāng)著我的面吹牛滨巴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俺叭,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恭取,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了熄守?” 一聲冷哼從身側(cè)響起蜈垮,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎裕照,沒(méi)想到半個(gè)月后攒发,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牍氛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年晨继,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搬俊。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡紊扬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唉擂,到底是詐尸還是另有隱情餐屎,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布玩祟,位于F島的核電站腹缩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏空扎。R本人自食惡果不足惜藏鹊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望转锈。 院中可真熱鬧盘寡,春花似錦、人聲如沸撮慨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至影涉,卻和暖如春变隔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蟹倾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工匣缘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喊式。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓孵户,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親岔留。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夏哭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353