ES6新特性 iterators and Generators

ES6中引入了許多新特性姐赡,目前大量的JavaScript項目已經(jīng)使用了ES6來進行開發(fā)硼啤,那么熟悉這些新的特性是十分必要的何暇,例如Redux-Saga中大量的使用了Iterator和generator挽懦。這篇文章總結(jié)和介紹一下ES6中的Iterator和Generator秕铛。

iterators and Generators

第一個問題什么是iterator二跋?答案很簡單粗悯, Iterator是一個object,但是含有特定的接口同欠,它有next method可以返回一個result object样傍,這個result object有兩個屬性第一個是value,代表這個迭代的值, 第二個是done铺遂,代表迭代是否結(jié)束衫哥。如果我們自己來簡單實現(xiàn)一個Iterator,它是這樣的襟锐。

function createIterator(items) {
    var i = 0;
    return {
        next : function () {

            var done = i >= (items.length)
            var value = items[i++]

            return {
                done: done,
                value: value
            }
        }
    }
}

const items = [1,2,3]
const iteratorA = createIterator(items)
iteratorA.next() // {result:1, done: false}

那么Generator又是什么撤逢?Generator 是一個函數(shù)可以產(chǎn)生iterator。Generator函數(shù)用function關(guān)鍵字后邊帶*來表示。在函數(shù)定義上使用yield關(guān)鍵字來表示next方法調(diào)用時返回的值蚊荣。例如

function *createIterator(){
    yield 1;
    yield 2;
    yield 3;
}

let iterator = createIterator();
console.log(iterator.next().value);  //1
console.log(iterator.next().value);  //2
console.log(iterator.next().value);  //3

iterables

上邊介紹了什么是Iterator初狰,什么是generator,下邊再介紹一個概念iterable互例。iterable是一個有Symbol.iterator屬性的object奢入。這個symbol指向一個generator函數(shù),這個函數(shù)返回關(guān)于這個對象的iterator媳叨。在ES6中所有的集合類對象(array, set, maps)和字符串都是iterable腥光,并且有自己默認的iterator。當我們在使用 for-of時候?qū)嶋H上是利用了這些對象上的iterator,每次調(diào)用了next方法糊秆,將返回的result上的value返回回來武福。

let values = [1, 2, 3];
for (let num of values) { 
    console.log(num);
}

例如這段簡單的代碼,實際上調(diào)用了values上的iterator的next方法痘番,將result上的value拿出來賦給num捉片。既然是這樣我們可以采用這樣的方法來獲得默認的iterator。

let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();

在ES6中對于集合類型的Object,其上定義了一些內(nèi)置的iterator汞舱,分別是伍纫;

  • entries() - 返回一個返回key-value pair的iterator
  • values() - 返回一個返回collection對應(yīng)值的iterator // chrome not supported
    MDN
  • keys() - 返回一個返回collecttion對應(yīng)key的iterator

以上就是iterator和generator的一些基本概念,下邊我們來看一下一些高階應(yīng)用兵拢。

向iterator中傳遞參數(shù)

上邊的例子中我們在調(diào)用iterator的next方法都是無參數(shù)調(diào)用的,但是我們同樣可以向next方法中傳遞參數(shù)逾礁。例如這樣说铃。

function* createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let i= createItreator()

i.next() // {value:1 done: false}
i.next(5) // {value: 7 done: false}
i.next(3) // {value: 6 done: false}

我們看上邊這個例子,在第二次調(diào)用中我們傳進去了5,返回值是7嘹履,這個傳進去的參數(shù)可以理解為上一次yield的返回值腻扇。注意yield本身是不返回任何值的,它只向外部產(chǎn)生值砾嫉。如果我們查看yield在英語詞典中的意思幼苛,produce or generate (a result, gain, or financial return 所以yield的值是向外產(chǎn)生值。所以在第一次next后 first的值依舊是undefined焕刮。但是向next中傳遞參數(shù)舶沿,這個參數(shù)代表我們想要上一次yield在generator函數(shù)中的值。所以在第二次next后 返回值的value就是7(5+2)了配并。第三例子同理括荡。所以基于上邊的原因我們向第一個next函數(shù)中傳入任何值都是沒有意義的。我們變化一下再看

function* createIterator() {
    yield 1;
    let first;
    let second = yield first + 2;
    yield second + 3;
}

i.next() // {value:1 done: false}
i.next(5) // {value: NaN done: false}
i.next(3) // {value: 6 done: false}

在第二個next中我們的返回是NaN, 為什么呢溉旋?這是因為first是Undefined畸冲,第一次的yield并沒有給first賦值。所以在yeild中的執(zhí)行順序是每一次執(zhí)行到相應(yīng)的yield就完了,下次繼續(xù)向下執(zhí)行邑闲。

在Iterator中Throw Error

在iterator中我們可以來throw error 來達到控制執(zhí)行的目的算行。例如上邊一個例子。

function* createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let i= createItreator()

i.next() // {value:1 done: false}
i.next(5) // {value: 7 done: false}
i.throw(new Error('error')) // error thrown done is set to true after throw error

Generator function中的Return

同樣在generator 我們可以使用 return來返回苫耸。

function* createIterator() {
    yield 1;
    return;
    yield 2;
    yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

第一次next后已經(jīng)結(jié)束了所以 我們第二次next后done就已經(jīng)是true了州邢。

Generator 和 Iterator的應(yīng)用實例:Task Runner

我們可以使用generator和Iterator來實現(xiàn)一個task runner,可以讓我們不用手動的next,而是一次執(zhí)行結(jié)束鲸阔。代碼如下:

function run(taskDef) {
    let task = taskDef();
    let value = task.next()

    function step() {
        if (!value.done) {
            value = task.next(value.value)
            step()
        }
    }

    step()
}

run(function*(){
    let first = yield 1;
    let second = yield first + 3;
    yield second + 4;
})

上邊就是一個例子偷霉,這樣定義的run function就可以順序執(zhí)行這些generator定義的步驟。

實際上generator和Iterator最為實際的作用是可以控制異步函數(shù)的執(zhí)行褐筛,下邊我們可以簡單的例子类少。

function run(taskDef) {
    let task = taskDef();
    let result = task.next()

    function step() {
        if (!result.done) {
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        console.log('err', err);
                        task.throw(err)
                        return
                    }
                    console.log('err', data);  
                    result = task.next(data);
                    step()
                    
                })
            } else {
                result = task.next(result.value)
                step()
            }
            
        }
    }

    step()
}

let fs = require("fs");

function readFile(filename) {
  return function (callback) {
    fs.readFile(filename, callback);
  };
}

run(function* () {
  let contents = yield readFile("abc.json");
  console.log(contents);
  console.log("Done");
});

首先我們定義了一個task runner run function 在其中當發(fā)現(xiàn)result中的value是function的時候,就執(zhí)行這個function, 并且在異步函數(shù)的callback中渔扎,當沒有error的時候執(zhí)行下一步硫狞。

在看我們的ReadFile function,fs模塊中的readFile是一個異步的函數(shù)晃痴,而在這里我們將其進行了封裝成為一個新的函數(shù)残吩。讓其返回一個function給在task runner中使用。那么在我們的generator函數(shù)中倘核,我們看上去的代碼就和同步的一樣了泣侮,先readfile,完成后將其輸出紧唱。這樣使用Iterator和generator可以幫助我們寫出一個比較好看的異步執(zhí)行函數(shù)活尊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市漏益,隨后出現(xiàn)的幾起案子蛹锰,更是在濱河造成了極大的恐慌,老刑警劉巖绰疤,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铜犬,死亡現(xiàn)場離奇詭異,居然都是意外死亡轻庆,警方通過查閱死者的電腦和手機癣猾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余爆,“玉大人煎谍,你說我怎么就攤上這事×耄” “怎么了呐粘?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵满俗,是天一觀的道長。 經(jīng)常有香客問我作岖,道長唆垃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任痘儡,我火速辦了婚禮辕万,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沉删。我一直安慰自己渐尿,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布矾瑰。 她就那樣靜靜地躺著砖茸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殴穴。 梳的紋絲不亂的頭發(fā)上凉夯,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音采幌,去河邊找鬼劲够。 笑死,一個胖子當著我的面吹牛休傍,可吹牛的內(nèi)容都是我干的征绎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼磨取,長吁一口氣:“原來是場噩夢啊……” “哼人柿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寝衫,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤顷扩,失蹤者是張志新(化名)和其女友劉穎拐邪,沒想到半個月后慰毅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡扎阶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年汹胃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片东臀。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡着饥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惰赋,到底是詐尸還是另有隱情宰掉,我是刑警寧澤呵哨,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站轨奄,受9級特大地震影響孟害,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挪拟,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一挨务、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玉组,春花似錦谎柄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吨凑,卻和暖如春捍歪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鸵钝。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工糙臼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恩商。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓变逃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怠堪。 傳聞我的和親對象是個殘疾皇子揽乱,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 在此處先列下本篇文章的主要內(nèi)容 簡介 next方法的參數(shù) for...of循環(huán) Generator.prototy...
    醉生夢死閱讀 1,439評論 3 8
  • 簡介 基本概念 Generator函數(shù)是ES6提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同粟矿。本章詳細介紹...
    呼呼哥閱讀 1,070評論 0 4
  • 異步編程對JavaScript語言太重要凰棉。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程陌粹,根本...
    呼呼哥閱讀 7,301評論 5 22
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持撒犀,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠掏秩,并抽取幸運大...
    HetfieldJoe閱讀 1,023評論 0 0
  • “注意力”這個詞或舞,我們認識了很多年,也用了很多年 蒙幻,但是從來沒有覺得注意力這個詞對我們的一生有多么的重要映凳。 自從跟...
    冬日陽光88閱讀 171評論 4 1