Help us understand the problem. What is going on with this article?

async await の使い方

More than 1 year has passed since last update.

これからはasync,awaitが読み書きできないと生きていけなそうだったので調べてみました。
※コード例は一応TypeScriptですが、ほとんどJavaScriptです。
参考: async function - JavaScript | MDN

async

asyncを関数の宣言の前に付けると、その関数は必ずPromiseを返します。
すなわち、呼び出して結果を取得するためには必ず関数().then(result=>{ ... })を使うようになります。

before
function fn() {
  return 42;
}

let result = fn();
console.log(result);
after
async function fn() {
  return 42;
}

fn().then(result => {
  console.log(result);
});

async関数でPromise以外の値を返した場合は、その値でresolveされるPromiseが返るようになります。
この挙動はどこかで見覚えがあります。そう、Promise.then(result=>{ ... })...部分と同じです!

もちろん、async関数で今まで通りの方法でPromiseを返すこともできます。

async function fn() {
  return new Promise((resolve, reject) => {
    resolve(42);
  });
}

fn().then(result => {
  console.log(result);
});

await

asyncを付けた関数の中では、await PromisePromise.then(result=>{ ... })を簡略化した書き方として使えるようになります。async関数の中ではないトップレベル等の場所ではこの書き方はできないので注意しましょう。

before
async function fn() {
  return 42;
}

async function exec() {
  fn().then(result => {
    console.log(result);
  });
}

exec();
after
async function fn() {
  return 42;
}

async function exec() {
  let result = await fn();
  console.log(result);
}

exec();

これにより、Promise.then()のチェインが通常の同期処理の流れと同じように書くことができるようになります。

before
// delayミリ秒待機する。任意の第二引数を結果として返す。
async function sleep(delay, result?) {
  return new Promise(resolve => {
    setTimeout(() => resolve(result), delay);
  });
}

async function exec() {
  sleep(1000)
    .then(() => console.log(1))
    .then(() => sleep(2000, 42))
    .then((result) => console.log(result))
}

exec();
after
// delayミリ秒待機する。任意の第二引数を結果として返す。
async function sleep(delay, result?) {
  return new Promise(resolve => {
    setTimeout(() => resolve(result), delay);
  });
}

async function exec() {

  // 非同期処理を実行するだけ
  await sleep(1000)
  console.log(1);

  // 非同期の結果を受け取る
  let result = await sleep(2000, 42)
  console.log(result);
}

exec()

この書き方では、Promiseの処理を順番に処理したり並行処理したりするのを簡単に書き分けることができます。従来の方法では並行処理はPromise.all()で書けますが、順番に処理するのは結構大変でした。なので、これはかなり便利です。

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function add1(x) {
  var a = resolveAfter2Seconds(20);
  var b = resolveAfter2Seconds(30);
  return x + await a + await b; // 2秒待つのと2秒待つのが並行で行われる
}

add1(10).then(v => {
  console.log(v);  // 2秒後に60と表示
});

async function add2(x) {
  var a = await resolveAfter2Seconds(20); // ここで2秒待つ
  var b = await resolveAfter2Seconds(30); // さらに2秒待つ
  return x + a + b;
}

add2(10).then(v => {
  console.log(v);  // 4秒後に60と表示
});

もう一つのawaitのすごいところは、Promiseの例外ハンドリングをtry { ... } catch { ... }で書けるところです。

before
function getProcessedData(url) {
  return downloadData(url) // returns a promise
    .catch(e => {
      return downloadFallbackData(url) // returns a promise
    })
    .then(v => {
      return processDataInWorker(v); // returns a promise
    });
}
after
async function getProcessedData(url) {
  let v:
  try {
    v = await downloadData(url); 
  } catch (e) {
    v = await downloadFallbackData(url);
  }
  return processDataInWorker(v);
}
niusounds
iOSエンジニアLv1。AndroidはLv10くらい。
http://www.niusounds.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした