8
10

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.

ES2017でawaitのネストを避ける

Last updated at Posted at 2018-08-25

async/await前提のライブラリ(例:Puppeteer)を使っていると、awaitをネストしたくなることがあります。例えば次のような状況です。

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

class Foo {
  async getBar() {
    console.log('getBar()');
    return new Promise(resolve => resolve(new Bar()));
  }
}

class Bar {
  async baz() {
    console.log('baz()');
    await sleep(5000);
    console.log('baz finished');
  }
}

(async () => {
  const foo = new Foo();
  await (await foo.getBar()).baz();
})();

Barオブジェクトのメソッドbaz()をawaitしたいが、そのBarオブジェクトを得るのにfoo.getBar()をawaitで受け取る必要がある、という状況です。

個人的には、この例のようにawaitがネストしているとカッコ悪いなあ、と感じてしまいます。

await foo.getBar()を一回変数に受け取ってもいいんですけど、他に書き方は無いのだろうか、ということで考えてみました。

thenでメソッドチェーンする

下記のようにすればawait1回でやりたいことが実現できます。

(async () => {
  const foo = new Foo();
  await foo.getBar()
    .then(x => x.baz());
})();

このように書くとthen()の返すPromiseをawaitすることになるので、awaitでthen()の終了を待つことになります。

これで読みやすくなったかは疑問ですが、awaitが三重四重になるようであればこのような書き方もアリかなと思います。

Puppeteerでの実例

上のような状況の例としてPuppeteerのコードを示します。

Puppeteerで、ページ中の要素の出現を待ってクリックする、というような状況では次のようなコードを書くことがあります。

const button = await page.waitForSelector('button[type="submit"]', {visible: true});
await button.click();

これを1行で書きたいとき、次のように書くことができます。

await page.waitForSelector('button[type="submit"]', {visible: true})
  .then(el => el.click());

Puppeteerでのコーディングではセレクタ1個にそれほど重要な意味はないので、いちいち変数に取りたくない気持ちになるんですよね。

8
10
0

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
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?