20

私は今日、node.js ミートアップに参加しました。そこで会った人が、node.js には es6 ジェネレーターがあると言いました。彼は、これはコールバック スタイルのプログラミングを大幅に改善したものであり、ノードのランドスケープを変えるだろうと述べました。Iirc、彼はコール スタックと例外について何か言いました。

私はそれらを調べましたが、初心者に優しい方法でそれらを説明するリソースは実際には見つかりませんでした. ジェネレーターの概要と、コールバックとの違い (または優れている点) は何ですか?

PS: コードのスニペットを提供して、一般的なシナリオ (http 要求または db 呼び出しを行う) の違いを強調できれば、非常に役立ちます。

4

5 に答える 5

10

ジェネレーターは、今後の ES6の多くの機能の 1 つです。そのため、将来的にはブラウザで使用できるようになります (現在は FF でプレイできます)。

ジェネレーターはイテレーターのコンストラクターです。ちんぷんかんぷんなように聞こえるので、簡単に言えば、メソッドを使用して for ループのようなもので後で反復できるオブジェクトを作成できます.next()

ジェネレーターは、関数と同様の方法で定義されます。*彼らが持っていることを除いてyield。* はこれがジェネレータであることを示すためのもので、yield は return に似ています。

たとえば、これはジェネレーターです:

function *seq(){
    var n = 0;
    while (true) yield n++;
}

次に、このジェネレーターを で使用できますvar s = seq()。ただし、関数とは対照的に、すべてを実行して結果を返すわけではなく、ジェネレーターをインスタンス化するだけです。s.next()ジェネレーターを実行するときにのみ実行されます。ここで、yield は return に似ていますが、yield が実行されると、ジェネレーターが一時停止し、次の次の式の処理が続行されます。しかし、次s.next()が呼び出されると、ジェネレーターは実行を再開します。この場合、いつまでも while ループを続けます。

だからあなたはこれを繰り返すことができます

for (var i = 0; i < 5; i++){
  console.log( s.next().value )
}

または、ジェネレーターの特定の of コンストラクトを使用します。

for (var n of seq()){
    if (n >=5) break;
    console.log(n);
}

yield*これらは、ジェネレーターに関する基本事項です ( 、next(with_params)throw()およびその他の追加の構造を見ることができます)。これはES6のジェネレーターに関するものであることに注意してください(したがって、ノードとブラウザーでこれをすべて実行できます)。

しかし、この無限数列がコールバックとどのように関係しているのでしょうか?

ここで重要なことは、yield がジェネレーターを一時停止することです。このように動作する非常に奇妙なシステムがあると想像してください:

ユーザーのデータベースがあり、ID を持つユーザーの名前を見つける必要がある場合、ファイル システムでこのユーザーの名前のキーをチェックインする必要があります。次に、ユーザーの ID とキーを使用して FTP に接続する必要があります。接続後に何かをします。(ばかげているように聞こえますが、ネストされたコールバックを表示したい)。

以前は、次のように記述していました。

var ID = 1;
database.find({user : ID}, function(userInfo){
    fileSystem.find(userInfo.name, function(key){
        ftp.connect(ID, key, function(o){
            console.log('Finally '+o);
        })
    })
});

これは、コールバック内のコールバック内のコールバックです。これで、次のように書くことができます:

function *logic(ID){
  var userInfo  = yield database.find({user : ID});
  var key       = yield fileSystem.find(userInfo.name);
  var o         = yield ftp.connect(ID, key);
  console.log('Finally '+o);
}
var s = logic(1);

ご覧のとおり、with s.next();ネストされたコールバックはありません。

ノードはネストされたコールバックを頻繁に使用するため、これが、ジェネレーターがノードのランドスケープを変更できると担当者が言っていた理由です。

于 2014-07-26T02:50:46.753 に答える
10

ジェネレーターは、 anIteratorと anの 2 つの組み合わせですObserver

イテレータ

イテレータは、呼び出されたときに反復可能なものである iterable を返すものです。ES6 以降、すべてのコレクション (Array、Map、Set、WeakMap、WeakSet) は Iterable コントラクトに準拠しています。

ジェネレーター(イテレーター)はプロデューサーです。反復では、消費者PULLは生産者からの値です。

例:

function *gen() { yield 5; yield 6; }
let a = gen();

を呼び出すたびにa.next()、基本的pullにイテレータからの値とpauseでの実行を行っていyieldます。次に を呼び出すとa.next()、以前に一時停止した状態から実行が再開されます。

観察者

ジェネレーターはオブザーバーでもあり、これを使用していくつかの値をジェネレーターに送り返すことができます。例を挙げてよりよく説明しました。

function *gen() {
  document.write('<br>observer:', yield 1);
}
var a = gen();
var i = a.next();
while(!i.done) {
  document.write('<br>iterator:', i.value);
  i = a.next(100);
}

yield 1ここでは、 が何らかの値に評価される式のように使用されていることがわかります。評価される値は、a.next関数呼び出しに引数として送信される値です。

したがって、最初に生成されi.valueた最初の値 ( 1) になり、次の状態への反復を続行するときに、 を使用してジェネレーターに値を送り返しますa.next(100)

これは Node.JS のどこで使用できますか?

spawnジェネレーターは(taskJS または co の) 関数と共に広く使用されており、この関数はジェネレーターを取り込み、非同期コードを同期的に記述できるようにします。これは、非同期コードが同期コードに変換されたり、同期的に実行されたりするという意味ではありません。のように見えるコードを書くことができることを意味しますsyncが、内部的にはまだasyncです。

同期がブロックされています。非同期は待機中です。ブロックするコードを書くのは簡単です。PULL すると、割り当て位置に値が表示されます。PUSHするとコールバックの引数位置に値が現れる

イテレータを使用するとPULL、プロデューサーから値が取得されます。コールバックを使用すると、プロデューサーPUSHは値をコールバックの引数位置に渡します。

var i = a.next() // PULL
dosomething(..., v => {...}) // PUSH

ここでは、コールバックから値を取得a.next()し、2 番目にコールバック関数の引数位置に値を入力します。v => {...}PUSHv

このプル/プッシュ メカニズムを使用して、次のような非同期プログラミングを記述できます。

let delay = t => new Promise(r => setTimeout(r, t));
spawn(function*() {
  // wait for 100 ms and send 1
  let x = yield delay(100).then(() => 1);
  console.log(x); // 1

   // wait for 100 ms and send 2
  let y = yield delay(100).then(() => 2);
  console.log(y); // 2
});

したがって、上記のコードを見ると、blocking(yield ステートメントが 100 ミリ秒待機してから実行を継続する) ように見える非同期コードを書いていますが、実際にはwaiting. generatorのpauseandresumeプロパティにより、この驚くべきトリックを実行できます。

それはどのように機能しますか?

spawn 関数はyield promise、ジェネレーターから promise の状態を PULL するために使用し、promise が解決されるまで待機し、解決された値をジェネレーターに PUSH して、それを消費できるようにします。

今すぐ使う

したがって、ジェネレーターと spawn 関数を使用すると、NodeJS のすべての非同期コードをクリーンアップして、同期しているように見えるようにすることができます。これにより、デバッグが容易になります。コードもスッキリ見えます。

ところで、これは ES2017 用にネイティブに JavaScript に導入されます - as async...await. ただし、ライブラリで定義されている spawn 関数 (taskjs、co、または bluebird) を使用して、ES2015/ES6 および ES2016 で現在それらを使用できます。

于 2015-08-16T22:03:50.757 に答える
0

node で ES6 ジェネレーターを使用するには、 node >=0.11.2またはiojsをインストールする必要があります。

ノードでは、調和フラグを参照する必要があります。

$ node --harmony app.js 

または、generators フラグを明示的に参照することもできます

$ node --harmony_generators app.js

iojs をインストールしている場合は、harmony フラグを省略できます。

$ iojs app.js

ジェネレーターの使用方法の概要については、この投稿をご覧ください。

于 2015-01-29T10:48:00.563 に答える