ES6中的迭代器、Generator函數以及Generator函數的異步操做

最近在寫RN相關的東西,其中涉及到了redux-saga ,saga的實現原理就是ES6中的Generator函數,而Generator函數又和迭代器有着密不可分的關係。因此本篇博客先學習總結了iterator相關的東西,而後又介紹了Generator相關的內容,最後介紹了使用Generator進行異步編程。本篇博客所涉及的示例使用TypeScript語言編寫,固然所涉及的特性是基於ES6規範的,使用TS語言不影響來闡述和總結ES6的相關特性。下篇博客準備系統梳理一下saga相關的內容。編程

 

1、迭代器

以前再聊迭代器模式時,使用Swift語言自定義過迭代器,在TS中也有迭代器。此處的迭代器與以前所介紹的迭代器是大同小異的。首先咱們先來自定義一個迭代器,而後再看一下ES6中的迭代器的使用方式。redux

一、自定義迭代器

下方定義了一個迭代器函數,函數說明以下:數組

  • 該函數接收一個數組類型的參數,咱們能夠將須要建立迭代器的數組做爲參數傳進來。
  • 函數內部定義了一個 nextIndex 參數用來記錄迭代器的位置。
  • 該函數返回一個迭代器對象,該迭代器對象包含一個key爲 next , value爲匿名函數的屬性。
  • 這個key爲 next 的匿名方法的返回值爲每次迭代器的返回結果對象,這個結果對象由 兩個屬性組成,value表示本次迭代器的值,done表示迭代器遍歷是否結束。
  • 遍歷到最後,最終返回的值爲 { value: undefine, done: true }, 也就意味着迭代器遍歷結束,value是undefined, done爲true。  

 

自定義完迭代器後,咱們就能夠對上述代碼進行測試了。網絡

  • 首先建立了一個數組,而後將數組傳給 makeIterator 函數。而 makeIterator 函數會返回一個含有next方法的迭代器對象。
  • 咱們將這個迭代器對象命名爲 iterator,咱們就能夠經過 iterator的next方法來依次獲取數組中的值了。
  • 咱們經過 while 循環來不斷的調用 iterator中的next方法,直到next方法返回的對象中的done值爲true時,表示遍歷結束。
  • 遍歷結束後,咱們再次調用 next() 方法,獲得的是{ value: undefind, done: true } 的對象,表示遍歷結束,獲取的value值爲 undefined。

 

二、ES6中的迭代器

相似於Swift語言的特性,ES6規範中咱們能夠直接經過一些對象獲取該對象所對應的迭代器,以下所示:異步

  • 下方示例中使用的數組和上面使用的list是一個,首先咱們經過 list[Symbol.iterator]() 的方式獲取了 list對應的迭代器。(Symbol也是一種數據類型, 該數據類型用來表示獨一無二的對象)
  • 該迭代器的使用方式和輸出結果與上述咱們自定義的迭代器的使用方式徹底一致, 輸出結果與以前的結果也是一致的。

 

三、使用 for - of 遍歷迭代器

上述方式建立的迭代器咱們是使用的while循環來進行遍歷的,除了while循環,咱們還能夠經過for-of 進行遍歷。此處的 for - of遍歷方式相似於Swift語言中的 for - in循環,能夠依次的自動去除迭代器中的值。下方就是使用for - of 來循環遍歷建立的迭代器。異步編程

從下方示例中咱們不難看出直接輸出的是迭代器返回對象的value值。函數

 

四、在類中添加迭代器

咱們能夠在本身的類中添加相關方法,使咱們本身的類支持迭代器。下方就建立了一個 RangeIterator 類,該類的做用是能夠定義一個範圍,構造器能夠接受兩個值,一個是範圍的起始位置另外一個是範圍的結束點。下方咱們爲該範圍類添加了自定義迭代器,具體說明以下:學習

  • 在該類中添加了一個名爲 next 的箭頭函數,在該函數中作的事情與以前咱們自定義的next方法差很少,主要是用來獲取下一個值而後返回。
  • 而後又實現一個 [Symbole.iterator]函數,用來獲取迭代器對象。
  • 最後咱們可看到定義的範圍對象能夠向迭代器那樣使用for-of進行遍歷。

 

 

五、調用迭代器的場景

迭代器的使用場景仍是蠻多的,解構賦值、擴展運算符、Generator函數、yield*, 下方會簡單的列舉出來。測試

(1)、對數組或者集合的解構賦值

在下方代碼片斷中首先建立了一個名爲 mySet 的集合對象。而後經過循環給集合中添加了一些值。而後經過 解構賦值 的形式,取出了 mySet 中的第一個值和第二個值。此刻的結構賦值會調用集合的迭代器接口,取出第一個值和第二個值,分別賦值給 first 和 second。spa

第二個紅框中在結構賦值是使用了擴展運算符,該操做符會使 others 接收 firstItem 剩下的值。

 

(2)、擴展運算符 ...  

接下來來看另外一個擴展運算符的例子。

  • 首先定義了一個字符串,而後經過擴展運算符將該字符串的每一個字符拆分到一個數組中,輸出結果以下所示。
  • 擴展運算符還可使用到對象上,如第二個示例所示。

 

(3)、在Generator函數的 yield * 中使用

稍後會詳細的介紹 Generator 函數,一個Generator 函數返回的是一個迭代器,咱們能夠調用該迭代器的 next 方法來執行每個 yield。在 Generator 函數中,可使用 yield * 後邊跟一個可便遍歷的結構,這樣咱們就能夠在外部統一使用 next 來訪問這個可遍歷的結構的每個值,以下所示:

 

 

2、Generator函數及異步編程

理解完迭代器,接下來來看一下Generator函數。若是作過RN開發的話,若是使用過 redux - saga的話,應該對Generator函數不陌生。Generator函數是ES6提供的異步編程的解決方案,解析了咱們先看一下Generator函數基本使用方式,再看一下如何使用Generator函數進行異步編程。

一、Generator函數的定義和使用

下方定義了一個 Generator函數,Generator函數的定義與普通函數的定義差很少,只不過是function關鍵字後邊跟了一個*號。而後函數體內部使用了一個個 yield語句來代表每一步的操做。定義完Generator函數後,下方緊接着的是使用,首先調用該Generator函數獲取了一個迭代器,每次執行這個迭代器的next方法都會一次的執行一個yield語句。輸出結果和上面的迭代器沒啥區別。

 

二、next的參數

在調用Generator函數返回的迭代器時,是能夠往next方法中傳入參數的。next 方法能夠帶一個參數,該參數被當作上一個 yield 語句的返回值。下方就是給 next 傳參的一個示例:

  • 下方定義了一個Generator函數,用來輸出自增的值,每次調用next都會獲取一個自增的值。
  • 當調用 rg.next(true) 時,這個true就會被賦值給 reset, 由於這個reset被視爲上個yield的返回值,上一個yield執行後,會將index設置爲 -1
  • 那麼rg.next(true)對應的 yield執行是,index是從 -1 開始自增的,自增後爲0,因此 rg.next(true) 對應的 yield 的值爲0。

 

下方是另外一個示例:

  • 下方定義了一個名爲testNextValue的Generator函數,該函數自己接收了一個參數。
  • 在調用該Generator函數時,傳入了一個參數,這個參數不是Next的參數,是Generator函數自己的參數。Generator函數在調用時,函數體並不會立刻執行,在調用next函數時纔會執行函數中yield語句體。
  • 第一次調用Next,給Next傳入了一個值 5,也就是說明 x = 5。第一次執行next會調用第一個 yield 語句體, test1.next(2) = x + 1 = 5 + 1 = 6, 因此第一次調用next的結果值爲 6
  • 第二次調用 Next,傳入的Next參數爲3。這個3 被做爲上一個 yield 語句體的返回值,yield(x + 1) 的返回值爲 3。那麼 y 的值就爲 2 * 3 = 6。yield中的值爲 y / 3 = 2因此第二次執行next獲取的值爲 2
  • 第三次調用Next傳入的參數爲 4,這個 4 被做爲上個yield語句體返回的參數,因此z = 4, 上分析過了 x = 5, y = 6, 因此 x + y + z = 15, 第三次執行next爲 15
  • 再次調用Next,由於語句體執行完了,因此獲取到的是undefined。

 

 

3、使用Generator函數進行異步編程

接下來實現一個簡單的示例,使用Generator函數結合Promise回調模擬一下異步編程。

首先定義了一個 getPromise函數,該函數接收兩個參數,一個參數表示網絡請求的參數,另外一個參數表示請求時間。該函數返回一個 Promise對象,在Promise對象中咱們使用了setTimeout來模擬請求的延遲,根據傳入的timeout來決定延遲時間,延遲時間到達後會執行 resolve方法,將相關值回調出來。

 

而後定義了一個Generator函數,在該函數中經過yield來調用每一個函數,下方的Generator函數比較簡單,在此就不作過多贅述了。 

 

而後咱們經過for -of 一次執行Generator函數的next方法,進而來執行每一個getPromise方法。

  

下方是具體的執行結果,從執行結果中不難看出,每次獲取的yield值是一個Promise對象,咱們可在該Promise對象的then方法中獲取到相關的結果值。從輸出順序中能夠看出,會先輸出時間小的那個結果。

 

本篇博客就先到這兒吧,下篇會聊一些saga的相關內容。

相關文章
相關標籤/搜索