ES6 系列九:Generator

"Code tailor",爲前端開發者提供技術相關資訊以及系列基礎文章,微信關注「小和山的菜鳥們」公衆號,及時獲取最新文章。

前言

在開始學習以前,咱們想要告訴您的是,本文章是對阮一峯《ECMAScript6 入門》一書中 "Generator" 章節的總結,若是您已掌握下面知識事項,則可跳過此環節直接進入題目練習javascript

  • 什麼是 Generator?
  • 如何建立和使用?
  • 如何在異步中應用?
  • 優缺點

若是您對某些部分有些遺忘,👇🏻 已經爲您準備好了!前端

學習連接

Generator 的學習java

Generator 的異步應用es6

彙總總結

概念

Generator函數是 ES6 中提供的一種 異步編程解決方案。語法上,首先能夠把它理解成, Generator 函數是一個 狀態機,封裝了多個內部狀態,須要使用 next()函數來繼續執行下面的代碼。

建立和使用

function* helloWorldGenerator() {
  yield 'hello'
  yield 'world'
  return 'ending'
}
var hw = helloWorldGenerator()
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }

經常使用方法

  • Generator.prototype.next()
next() 方法返回一個包含屬性 donevalue 的對象。該方法也能夠經過接受一個參數用以向生成器傳值

返回的對象包含兩個屬性:編程

  • done (布爾類型)
  • 若是迭代器超過迭代序列的末尾,則值爲 true。 在這種狀況下,value 可選地指定迭代器的返回值。
  • 若是迭代器可以生成序列中的下一個值,則值爲 false。 這至關於沒有徹底指定 done 屬性。
  • value - 迭代器返回的任意的 Javascript 值。當 done 的值爲 true 時能夠忽略該值。
function* gen() {
  yield 1
  yield 2
  yield 3
}

var g = gen() // "Generator { }"
g.next() // "Object { value: 1, done: false }"
g.next() // "Object { value: 2, done: false }"
g.next() // "Object { value: 3, done: false }"
g.next() // "Object { value: undefined, done: true }"
  • Generator.prototype.return()
return() 方法返回給定的值並結束生成器
function* gen() {
  yield 1
  yield 2
  yield 3
}
var g = gen()
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
  • Generator.prototype.throw()
throw() 方法用來向生成器拋出異常,並恢復生成器的執行,返回帶有 donevalue 兩個屬性的對象
  • done (布爾類型)
  • 若是迭代器已經返回了迭代序列的末尾,則值爲 true。在這種狀況下,能夠指定迭代器 value 的返回值。
  • 若是迭代可以繼續生產在序列中的下一個值,則值爲 false。 這至關於不指定 done 屬性的值。
  • value - 迭代器返回的任何 JavaScript 值。當 donetrue 的時候能夠省略。
function* gen() {
  while (true) {
    try {
      yield 42
    } catch (e) {
      console.log('Error caught!')
    }
  }
}

var g = gen()
g.next() // { value: 42, done: false }
g.throw(new Error('Something went wrong')) // "Error caught!"

在異步中的應用

var readFile = function (name, ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name + '讀完了')
      resolve()
    }, ms)
  })
}

var gen = function* () {
  console.log('指定generator')
  yield readFile('first', 1000)
  yield readFile('second', 2000)
  return '完成了'
}

var g = gen()
var result = g.next()
result.value
  .then(() => {
    g.next()
  })
  .then(() => {
    g.next()
  })

優缺點

優勢:數組

  • 能夠控制函數的執行,能夠配合 co 函數庫使用

缺點:微信

  • 流程管理卻不方便(即什麼時候執行第一階段、什麼時候執行第二階段)

更多知識請點擊JavaScript 異步發展史異步

題目自測

一:Generator 函數的 yield 關鍵字的做用是()?async

  • A: 中止執行
  • B: 退出函數
  • C: 暫停執行,等待 next()方法調用
  • D: 中止執行,可自行恢復執行

二:以下代碼執行後打印結果爲()異步編程

function* generator(i) {
  yield i
  yield i * 2
}

const gen = generator(10)

console.log(gen.next().value)
console.log(gen.next().value)
  • A: [0, 10], [10, 20]
  • B: 20, 20
  • C: 10, 20
  • D: 0, 10 and 10, 20

三:以下代碼執行後打印結果爲()

function* generatorOne() {
  yield ['a', 'b', 'c']
}

function* generatorTwo() {
  yield* ['a', 'b', 'c']
}

const one = generatorOne()
const two = generatorTwo()

console.log(one.next().value)
console.log(two.next().value)
  • A: a and a
  • B: a and undefined
  • C: ['a', 'b', 'c'] and a
  • D: a and ['a', 'b', 'c']

題目解析

1、

Answer:C

Generator 函數的調用方法與普通函數同樣,也是在函數名後面加上一對圓括號。不一樣的是,調用 Generator 函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,也就是上一章介紹的遍歷器對象(Iterator Object)。

下一步,必須調用遍歷器對象的 next 方法,使得指針移向下一個狀態。也就是說,每次調用 next 方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個 yield 表達式(或 return 語句)爲止。換言之,Generator 函數是分段執行的,yield 表達式是暫停執行的標記,而 next 方法能夠恢復執行。


2、

Answer:C

常規函數不能在調用後中途中止。可是,生成器函數能夠中途「中止」,而後從中止的地方繼續。每次生成器函數遇到yield關鍵字時,該函數都會生成它後面指定的值。注意,在這種狀況下,生成器函數不返回值,而是生成值。

首先,咱們初始化生成函數,使 i 等於 10。咱們使用next()方法調用生成器函數。第一次調用生成器函數時,i 等於 10。它遇到第一個 yield 關鍵字:它產生 i 的值。生成器如今是「暫停」的,10 被記錄。

而後,咱們使用next()方法再次調用該函數。它開始在以前中止的地方繼續,仍然是 i 等於 10。如今,它遇到下一個yield關鍵字,併產生 i*2i 等於 10,因此它返回 10*2,也就是 20。結果是 10,20


3、

Answer:C

使用yield關鍵字,咱們在生成器函數中產生值。 使用yield *關鍵字,咱們能夠從另外一個生成器函數或可迭代對象(例如,數組)中產生值。 在generatorOne中,咱們使用 yield 關鍵字產生整個數組['a','b','c']。 一個對象的下一個方法(one.next()。value)返回的對象的 value 屬性值等於整個數組['a','b','c']

console.log(one.next().value) // ['a', 'b', 'c']
console.log(one.next().value) // undefined

generatorTwo中,咱們使用yield *關鍵字。 這意味着咱們獲得的迭代器爲數組['a','b','c']。 第一個產生的值爲數組中的第一個值 a,所以咱們第一次調用two.next().value時,將返回 a。後面繼續調用next()則會持續返回bc直到該數組調用結束。。

console.log(two.next().value) // 'a'
console.log(two.next().value) // 'b'
console.log(two.next().value) // 'c'
console.log(two.next().value) // undefined
相關文章
相關標籤/搜索