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の中で、その存在の目的はもっと良いコントロールフローを書くことができます.
下記のコードがあると仮定します.
上の方
まずGEneratorをPromiseに戻す関数としてカプセル化します.
続けます
この二段階の処理を経て、
Generatorの概念は惰性求値であり、一時停止関数によって実行されることによって、開発者のコントロールプログラムの制御フローは早く値を求めるようになるのではなく、文がそこに来たらすぐに値を求める必要があります.
Generatorは他のコントロールフローの代替として使われている霊薬ではなく、ただ一つの可能性があります. の公式例をよく説明しました.
DOMの泡事件に似ていますか?
画像認識図の二次元コード(またはWeChat公衆番号FrontEnd Storyを検索する)に従って「先端のこと」に関心を持ち、最新の先端技術をご案内します.
前に紹介しました 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
右側の文の値は、そのようです. yield
、var 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を検索する)に従って「先端のこと」に関心を持ち、最新の先端技術をご案内します.