Node.js 101(3):generator


原文の住所――http://blog.chrisyip.im/nodejs-101-generator
前に紹介しました Promise and asyncは、ECMAScript 6が新しく加入したと言います. Generator
In computer science,a generatois a special routine that can be used to control the iteration behaviour of a loop.In fact,all generators ariterators.– Wikipedia
Generatorは、順番に実行される反復プログラムを非同期的に実行するように制御する方法である.Node.jsの中で、その存在の目的はもっと良いコントロールフローを書くことができます.
下記のコードがあると仮定します.
function loop (arr, cb) {
  for (let i = 0, len = arr.length; i < len; i++) {
    cb(arr[i])
  }
}
このコードを拡張する必要があるなら、より多くのフィードバックを追加します.
function loop (arr, cb) {
  for (let i = 0, len = arr.length; i < len; i++) {
    for (let j = 0, jlen = cb.length; j < jlen; j++) {
      cb[j](arr[i])
    }
  }
}

loop(arr, [cb1, cb2, cb3, cb4, ...cbN])
generatorに交換すればいいです.
function* loop (arr) {
  for (let i = 0, len = arr.length; i < len; i++) {
    yield arr[i]
  }
}

var ge = loop(['Phil Colson', 9])

var name = ge.next().value
  , profile = getProfile(name)
accessLog(name)

var accessLevel = ge.next().value
if (profile.level !== accessLevel) {
  throw new Error('You don\'t have privilege!')
}

if (ge.next().done) {
  loginDone(profile)
}
例から分かるように、generatorと一般の関数はあまり違いがありません.  function 後に星番号を付けてもいいです.最大の違いは、関数が直接呼び出されて結果を返します.ジェネナートは呼び出し後、作成して戻ってきます. のオブジェクトを通して  GeneratorFunctionPrototype メソッドを使用して、関数を実行して取得します.  next ステートメントの値:
function* ge () { yield 1 }
var g = ge()
g.next()
// { value: 1, done: false }
yield キーワードはgeneratorの核心であり、当  yield 呼び出された場合は、generator内のコードを実行します.  next 実行を停止し、次のyieldを待つ. の呼び出しは、すべてのコードが実行されるまで繰り返されます.これは関数非同期実行の能力を与えた.
function* ge () {
  console.log('called')
  yield 1
  console.log('yield called')
}
var g = ge()
g.next()
// 'called'
// { value: 1, done: false }
g.next()
// 'yield called'
// { value: undefined, done: true }
next 後は、値、オブジェクト、関数、または表式とすることができます.yield 呼び出し時に返されるnext デフォルトは  value 右側の文の値は、そのようです.  yieldvar x = yield 1 このような語句は?
function* ge () {
  var x = yield 10;
  console.log(x)
  return x + 5
}

var g = ge()
g.next()
// { value: 10, done: false }
g.next(1)
// 1
// { value: 6, done: true }

g = ge()
g.next()
// { value: 10, done: false }
g.next()
// undefined
// { value: NaN, done: true )
一番目  fn(yield ARGV) はい、そうです  next().value 右側の文の値、2番目の文の値  yield のパラメータが渡されます.  next() 左側の語句;もし  yield パラメータがないです.next()です.この特性を利用して、Promiseなどと組み合わせて、より便利な機能を実現できるという点を紹介します.undefined マークはすべてのコードが実行されましたか?
上の方  done ゲナートに改造した後、三つ.  loop それぞれ返しますge.next() { value: 'Phil Colson', done: false } { value: 9, done: false } 最後に注意してください.  { value: undefined, done: true } 呼び出し時、その  next generator functionの戻り値に等しい.  valueは、  return:
(function* demo () {
  return 'demo'
})().next()
// { value: 'demo', done: true }
Generatorの基礎紹介が終わり、generatorを利用して改造を開始しました. readFiles
まずGEneratorをPromiseに戻す関数としてカプセル化します.
// https://www.promisejs.org/generators/
function async (makeGenerator) {
  return function () {
    var generator = makeGenerator.apply(null, arguments);

    function handle(result){
      if (result.done) {
        return Promise.resolve(result.value);
      }

      return Promise.resolve(result.value).then(function (res){
        return handle(generator.next(res));
      }, function (err){
        return handle(generator.throw(err));
      });
    }

    try {
      return handle(generator.next());
    } catch (ex) {
      return Promise.reject(ex);
    }
  };
}
undefined 通過する  async 握り  next() 次へと伝える  value の中を通過します  Promise.resolve 結果を伝える  next(res) の左側にあるので、プログラムは同期して実行するプログラムのようになります.このステップを繰り返します.  yield までです
続けます  next().done === true のインターフェースをPromiseモードにしました.ここで使いました. fs-extra ブルーバードと この二つのライブラリ:
const Promise = require('bluebird'),
      fs = Promise.promisifyAll(require('fs-extra'))
経過  fs 処理したオブジェクトのすべての関数はPromiseモードにカプセル化され、パッケージされた関数は一般的に関数名の後に増加します.  bluebird.promisifyAll、例えばAsync.
この二段階の処理を経て、fs.readdirAsync 以下のように変換できます.
function* readFiles (opts) {
  var res = [], files

  files = yield fs.readdirAsync(opts.folder);

  for (var i = 0, len = files.length; i < len; i++) {
    var file = files[i],
        fullPath = path.resolve(opts.folder + '/' + file).replace(process.cwd(), '.'),
        stat = yield fs.statAsync(fullPath)

    if (stat.isDirectory()) {
      res = res.concat(
        yield async(readFiles)(_.assign({}, opts, { folder: fullPath }))
      )
    } else if (opts.pattern.test(file)) {
      res.push(fullPath)
    }
  }

  return res
}

function Sagase () {
  Object.defineProperties(
    this,
    {
      find: {
        enumerable: true,
        value: function (opts) {
          return async(readFiles)(formatOptions(opts))
        }
      }
    }
  )
}
このような処理後、readFiles 余分な入れ子が少なくなって、またあるべき非同期能力を残しました.
Generatorの概念は惰性求値であり、一時停止関数によって実行されることによって、開発者のコントロールプログラムの制御フローは早く値を求めるようになるのではなく、文がそこに来たらすぐに値を求める必要があります.
Generatorは他のコントロールフローの代替として使われている霊薬ではなく、ただ一つの可能性があります. の公式例をよく説明しました.
DOMの泡事件に似ていますか?
画像認識図の二次元コード(またはWeChat公衆番号FrontEnd Storyを検索する)に従って「先端のこと」に関心を持ち、最新の先端技術をご案内します.
Node.js 101(3): generator_第1张图片