2017-10-27

ECMAScript async/await 構文で記述する非同期処理

今年も終わりが見えてきた2017年の秋、最近はpromise.thenも過去のものになりつつあるようで。
今後は、async/awaitを使えるようになっておかないと、産廃扱いされそうなのでちょっと試してみます。

対応状況

2017年10月現在の対応状況は以下の通り。(MDNより)
IE及びモバイル版Safari以外はだいたい整っている。トランスパイルが使われなくなる日も近い?

[対応状況] (デスクトップ/モバイル)

Chrome - 55/55
Firefox - 52.0/52.0
Safari - 10.1/-
Edge   - ok
NodeJS - 7.6.0

async / await

Promiseでのフロー処理をすっきりさせるために、新しいメカニズムを追加するのではなく、シンタックスを拡張するよ、とのこと。

async関数 (関数をasync修飾すると...)
  • 呼び出し時にpromiseを返す
  • returnはPromise.resolveされる
  • 例外やthrowはPromise.rejectされる
  • await式を含むことができる
await式
  • async関数の実行を停止しpromiseの解決を待つ
  • resolveされた値を返しrejectされた値をthrowする

使用例

NodeJS v7.6.0を使用。 httpクライアントとしてthen-requestを追加。

async-await.js
const request = require('then-request');

const getPrice = async (symbol) => {
  console.log("->", "getPrice", symbol);
  let res = await request("GET", "https://api.bitfinex.com/v1/pubticker/" + symbol);
  let data = JSON.parse(res.getBody('utf-8'));
  return [symbol, data.last_price];
};


const asyncCall = async () => {
  // 並列 -- A
  try {
    let prices = await Promise.all([getPrice("btcusd"), getPrice("ethbtc")]);
    console.log(prices);
  } catch (e) {
    console.error(e);
  }

  // 直列 -- B
  try {
    let p1 = await getPrice("btcusd");
    let p2 = await getPrice("ethbtc");
    console.log([p1, p2]);
  } catch (e) {
    console.error(e);
  }
};

asyncCall();  // 非同期関数コール
console.log("->", "after");

出力は以下の通り。

-> getPrice btcusd
-> getPrice ethbtc
-> after
[ [ 'btcusd', '5706.9' ], [ 'ethbtc', '0.052051' ] ]
-> getPrice btcusd
-> getPrice ethbtc
[ [ 'btcusd', '5706.9' ], [ 'ethbtc', '0.052051' ] ]

callback地獄とthen地獄から開放されました。処理A-B間もシーケンシャルに実行されます。

直列処理をフラットに書けるのは見やすくて良いね。

参照