ES6のジェネレーターと新しい方法の非同期コード

ES6の取り扱いを開始したとき、ジェネレーターは、注目するイノベーションのリストのほぼ終わりに近づいています。 多くの場合、ジェネレーターをカスタムイテレーターを作成する簡単な方法と見なしますが、実際にははるかに興味深い機能を提供でき、ES6で最も興味深い革新の1つである可能性が高いです。



ジェネレーターとは何ですか?



ジェネレーターは、実行のさまざまな段階で開始、一時停止、再開できる機能です。 基本的に、この特別な関数は反復子を返します。 ジェネレーター関数は、 functionキーワードの後に​​アスタリスクで示され、特別なyieldキーワードを使用するとすべての魔法が隠されます。 next()メソッドの次の呼び出し後にイテレータが返すものを決定します。



そしてすぐに、ES6の単純なジェネレーターの例:



function* myGenerator() { yield 'first'; let input = yield 'second'; yield input; } //    let iterator = myGenerator(); //  ,    yield console.log(iterator.next()): // { value: 'first', done: false } // (   ),    yield console.log(iterator.next()); // { value: 'second', done: false } //  ( )    yield console.log(iterator.next('third')); // { value: 'third', done: false } //   (yield  ) console.log(iterator.next()); // { value: undefined, done: true }
      
      





ここで何が起こっているのでしょうか?





イテレーターとしてのジェネレーター



記事の冒頭で、ジェネレーターはイテレーターを作成するための単純なメカニズムとしてよく使用されることが言及されました。 これはすべてfor構文を使用して実行できます。



例:



 function* myGenerator() { yield 'first'; yield 'second'; yield 'third'; } for (var v of myGenerator()) { console.log(v); }
      
      





または例えば:



 function* myGenerator(start, stop) { for (var i = start; i < stop; i++) yield i; } for (var v of myGenerator()) { console.log(v); }
      
      





さて、イテレータは素晴らしいですが、ジェネレータを使用して何ができるか見てみましょう。



そのため、何らかのバックエンドにログインし、認証トークンを使用してAPIからデータを抽出する必要があります。 ジェネレーターメカニズムを適用すると、次のようになります。



 co(function* () { var result = yield login(username, password); var posts = yield getPosts(result.token); return posts; }).then(value => { console.log(value); }, err => { console.error(err); }); function login(username, password) { return fetch('/login', { method: 'post', body: JSON.stringify({ username: username password: password }) }).then(response => response.json()); } function getPosts(token) { return fetch('/posts', { headers: new Headers({ 'X-Security-Token': token }) }).then(response => response.json()); }
      
      





この例ではcoライブラリを使用します。これにより、promiseメカニズムを使用して、非同期コードが同期的に見えるようになります。 ここでは、各yieldについて、 promiseは結果をジェネレーター関数に返し、変数に保存します。



エクスプレスvsコア



えええ、コア? それは何ですか?



Koaは(公式サイトのサブタイトルからの) 新世代のフレームワークで 、同じジェネレーターとcoライブラリを使用してミドルウェアの書き込みメカニズムを改善し、 コールバックからアプリケーションを地獄から救います。
哲学的な観点から言えば、Koaは「ノードの修正と交換」を目指しており、Expressは「ノードの拡張」(Koaのドキュメントから)を目指しています。





Koaのミドルウェアは、ジェネレーターのメカニズムに基づいて構築され、「カスケード」を表します。 簡単に言えば、「ダウンストリーム」メカニズムはまずすべてのミドルウェアを介して開始され、次にすべてのミドルウェアを介して「アップストリーム」( 上流 )を開始します。



例:



 var koa = require('koa'); var app = koa(); // x-response-time app.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; this.set('X-Response-Time', ms + 'ms'); }); // logger app.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms); }); // response app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
      
      





この例は、「Hello World」を返しますが、最初に:



  1. リクエストはミドルウェアを通過しますx-response-timeyield次の行に行くすべてを行います
  2. 次に、 yield nextは現在の機能を停止し、制御を別のミドルウェアロガーに転送し、 yield nextまですべてを実行します
  3. ロガーでは、 yield nextは最後のミドルウェアを制御します。
  4. 彼は、順番に答えthis.body = 'Hello World'を生成します。
  5. ダウンストリーム送信用のミドルウェアはこれ以上ないため、 アップストリームプロセスが開始されます。 つまり 各ミドルウェアはyield nextの後に作業を再開し、アップストリームメカニズムを実現します。


一般的に言って、他に何がいいか。 Koaの詳細については、 公式Webサイトgithubを参照してください



おわりに



ES6のジェネレーターは、よりクリーンで理解しやすい非同期コードを作成できる強力なメカニズムです。 コード全体で多数のコールバックを使用する代わりに、同期のように見える非同期コードを作成できるようになりましたが、実際には、ジェネレーターとキーワードyieldの助けを借りて、非同期操作の完了を「待機」します。



All Articles