100
100

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ES async/awaitを全力で使ってみて発見したイディオム

Last updated at Posted at 2015-09-14

// 注意: 最初のバージョン、async function がundefinedを返すと思い込んでて、色々間違えてた

手元の趣味コード(諸事情により未公開)に向けて全力で適用してみた結果学びがあった。以下babel。

事前に確認

  • async/await は Promise と Generator の糖衣構文である
  • await は Promiseのインスタンスの式を与えると(見た目上)停止する
  • await するには async functionで囲う必要がある
  • async function は必ず非同期で実行され undefinedPromise を返す

以下イディオム

とりあえず実行したい

(async () => {
  await new Promise(done => {
    setTimeout(1000, done);
  })
})();

解説: async ブロック作ってからの即時実行。asyncブロックなしにawaitは呼べない。PubSubのSub側でreturn する必要がないときに何度か使った。

Promiseを返す関数の中で使う

fetchParamsは fetchParams() => Promise<Params> な関数だと思ってほしい。以下使いまわす。

// without async/await
function fetchXXX(){
  return fetchParams()
};

// with async/await
function fetchXXX(){
  return (async () => {
    const params = await fetchParams();
    return params;
  })();
};

解説: Promiseのラッパー関数がasyncブロックをとる。このままだと元のコードのほうが短くて見通しはいいんだけど、複数回 await する場合はthenで繋がない分、後者のほうが見通しがよくなる。

Promiseの直列化

// parallel without async/await
const p = Promise.all(items.map(item => fetchParamsByItem(item)));

// serial with async/await
const p = (async () => {
  const results = [];
  for (let item of items) {
      const params = await fetchParamsByItem(item);
      results.push(item);
  }
  return results;
})();

解説: 元の例がかなりショートコーディング気味だが、要は複数のPromiseをPromise.allで並列にさばいているという例。async/await版は直列なので遅くなっている。
注意すべきは、ここでただのmapを使うとコールバック関数によって async function から外れるので、for of で回している。 items.map(async (i) => {} みたいなコードも試したがasyncの中でasyncはbabelが例外を吐いてた。仕様の側に問題があるのかbabelに問題があるかはよくわかってないので誰か教えてくれ。

Promise関数の同期部分を待ってからawaitしたい

(async () =>{
  var p = fetchParams();
  app.registerPromiseWithPopup(p);
  await p;
})();

解説: app.registerPromiseWithPopup(p) は名前の通りpromiseを受け取って終了までポップアップでカバーをかける関数なのだが、最初のfetchParams() を await してしまうとpromiseのインスタンスが取得できない。一旦await するタイミングをずらす。

Mochaのテストケース

it('pass', async () => {
  const params = await fetchParams();
  assert.equal(params, {});
});

解説: テストケースは基本的に返り値要求されないので最初からasync関数として扱う
(実はmochaは最後にpromiseを受け取って終了を待てるのだが、非同期のハンドルという目的では同一なので使わなくて良い)

以上

async function は評価した時にfunction抜けた時にresolveされるPromiseを返してほしいなと思った。 Promise返してた。

あと見通し悪くなる可能性あるけど、awaitはどのノードでも使える式の方が嬉しい。結合順がややこしいが。
間違ってたら教えてほしい。

100
100
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
100
100

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?