JavaScript

ECMAScript 6を触ってみる – 非同期処理 PromiseとGeneratorによるフロー制御

投稿日:2017年5月19日 更新日:


前回に引き続きJSの速習コースを実践。今回は「WEB+DB PRESS Vol.87 第1特集 第5章-簡潔で柔軟な非同期処理-」を速習する。

PromiseとGeneratorによるフロー制御

これまでの非同期処理と新たな非同期処理

従来の非同期処理

上記コードの問題点は、2つの非同期処理が直列に実行されているにもかかわらず、コードがどんどんネストしていく為、フローが複雑になる。これによりエラー処理が複数の場所で必要になったり、callbackがすべての条件でもれなく実行されているか一見して把握することが難しくなる。

Promiseによる解決

Promiseによる非同期処理

  • ネストの改装が浅くなる
  • エラー処理のコードが減って見通しがよくなる
  • 以下のような取得したアイテムリストの全アイテムの詳細情報を並列に取得する処理も簡単に書ける

Promise.allを使った非同期処理

Generatorによるさらなる改善

Generatorを組み合わせることで同期処理のようなスタイルで非同期処理を書ける

Generatorをベースにしたライブラリcoを使うとネストとコールバックが消え、getUrlを同期処理関数のように扱うことができる

Promise

Promiseは非同期処理を抽象化する統一的なインターフェース

Promiseの基本

  • まずPromiseオブジェクトをPromiseコンストラクタで生成する
  • コンストラクタ引数にはresolveとrejectという2つの関数が渡される
  • resolveを実行するとPromiseオブジェクトにthenメソッドで登録したコールバック関数が実行される
  • resolveに指定した引数はコールバック関数の引数として渡される
  • thenメソッドは新たなPromiseオブジェクトを返すので、メソッドチェインにより連続して複数のコールバックを登録できる

Promiseのエラー処理

  • XMLHttpRequestで何らかのエラーが発生した場合、コンストラクタのコールバック関数の引数であるrejectを呼ぶ
  • これによりthenメソッドで登録した正常系のコールバックは呼ばれず、catchメソッドで登録したコールバックが呼ばれる

すべての非同期処理が終わるまで待つ

Promise.allを使えば複数のPromiseオブジェクトを配列で受けて、全てが完了したらコールバック関数を呼ぶPromiseオブジェクトを生成できる

  • /fooと/barに同時並行でリクエストを投げる
  • 両方のレスポンスが完了したら次のコールバック関数が呼ばれる
  • 複数のPromiseオブジェクトのうちどれか1つでも完了したらコールバックを呼ぶPromise.raceというスタティックメソッドもある

Generator

停止したり再開したりできる特殊な関数。またIterableインターフェースを実装していて、イテレータを生成できる関数でもある

Generatorの基本

  • ジェネレータ関数はfunctionキーワードと関数名の間に*を付けて定義する
  • yieldによってイテレーションの区切りを指定する
  • ジェネレータ関数を実行するとイテレータが返る
  • このイテレータのnextメソッドを呼ぶと、ジェネレータ関数の最初のyieldまで実行され、yield式の結果をvalueとして返す
  • ジェネレータ関数が生成するイテレータはIterableなので、for/ofなどIterableを期待する場面で利用できる

yieldに値を渡す

nextメソッドに値を渡すことでジェネレータ関数の外側から内側に値を渡すことができる

  • 変数ret1にyield式を代入している
  • このyield式の評価結果としてnext(“next 1”)の引数「next 1」が返る為、ret1に文字列「next1」が代入される
  • 最初のnextを読んだ時点でyield式に与えた代入式msg(“yield 1”)が実行される
  • 停止するのはyield式を変数ret1に代入する手前の時点

非同期処理との組み合わせ

Generatorはyieldとnextによって関数を停止・再開できたり、関数の呼び出し先と呼び出し元で値を交換できたりする

  • 本体のフロー自体をジェネレータ関数をして書き、フローの制御はasyncflowという関数に任せている
  • asyncflowはGeneratorのnextを呼び、本体のフローから非同期処理のPromiseをyield経由でもらう
  • そのPromiseが完了したら、thenのコールバックで次のnextを結果を渡しつつ呼ぶ

合わせて読みたい

最近のjs非同期処理 PromiseとGeneratorの共存

所感

最新の状況はまたどうなっているかわからないけど、promiseとgeneratorは実際に書いてみるとぱっと見た印象よりも簡潔に書けていい。generatorのyieldとnextによる関数の停止・再開の仕組みがおもしろい。


-JavaScript
-, , , , ,

執筆者:

関連記事

「slideship Tech Dive vol.1 フロントエンド特集」でLTしてきた

connpassリンク slideship Tech Dive v1.0 #React / ReactVR / #VueJs Webフロントエンド特集 「slideship Tech Dive v1. …

JavaScriptパターン

「JavaScriptパターン」第4章-関数-が面白かったからまとめながら写経した

タイトルにあるようにとても面白かったというのと、JavaScriptパターンの輪読会で第4章「関数」の後半を担当したのでその記録も兼ねて内容まとめながら写経した。 目次 はじめに 4.1 背景 4.2 …

ECMAScript 6を触ってみる – 標準化されたモジュール管理システム

前回に引き続きJSの速習コース実践ラスト。最後は「WEB+DB PRESS Vol.87 第1特集 第6章-標準化されたモジュール管理システム-」を速習する。 これまでのモジュール管理 JavaScr …

おれ的フロントエンド速習コース

3ヶ月でフロントエンド向上させるにあたって取り組んだことを書く。 フロントエンドって? どこからどこまで?何を指してる?と引っかかる人がいるかもしれないけどそこら辺はなんとなくお察しください。 3ヶ月 …

ECMAScript 6を触ってみる – モダンになった文法

WEB+DB PRESS Vol.87は、@t_wadaさんの言うとおりES6を速習するのにとても良い書籍だと思う。個人的には「JavaScript: The Good Parts ―「良いパーツ」に …