LoginSignup
5
8

More than 5 years have passed since last update.

Promise だけじゃない Async/Await の紹介

Last updated at Posted at 2017-07-07

はじめに Promise とは

JavaScriptの非同期処理は素晴らしいです、HTTPリクエストやDBの参照など待ち時間の発生する処理が入っても不必要に待つ必要はありません。言葉を変えると待ってくれません。

print.js
// A
console.log(1)

// B
setTimeout(() => {
  console.log(2)
}, 1000)

// C
console.log(3)
結果
1
3
2    #1秒後

BsetTimeout()内が実行されるのを待たずCが実行されるため
AC→1秒後にBsetTimeout内の処理 が実行されます。
AjaxのレスポンスやDBの問い合わせ結果が返ってくるまでがsetTimeout()に置き換わるイメージです。

コールバック関数内に次の処理を書けば意図した動作にはなるのですが、何度も繰り返すとネストが深くなりコールバック地獄になる。

callback.js
setTimeout(()=> {
  console.log(1)

  setTimeout(() => {
    console.log(2)

    setTimeout(() => {
      console.log(3)
    }, 1000)

  }, 1000)

}, 1000)
結果
1    #1秒後
2    #さらに1秒後
3    #さらに1秒後

Promiseを使うとネストせずに書ける。

promise.js
let A = () => {
  return new Promise(resolve => setTimeout(() => {
    console.log(1)
    resolve()
  }, 1000))
}

let B = () => {
  return new Promise(resolve => setTimeout(() => {
    console.log(2)
    resolve()
  }, 1000))
}

let C = () => {
  return new Promise(resolve => setTimeout(() => {
    console.log(3)
    resolve()
  }, 1000))
}

let promise = Promise.resolve()
promise.then(A).then(B).then(C)
結果
1    #1秒後
2    #さらに1秒後
3    #さらに1秒後

しかしpromise.then(A).then(B).then(C)と指定しては再帰やループが出来ない。
出来たとしても実装が難しい。これはHaskellなど関数型言語の思考に強く影響を受けてるからだとか。
(※書き方を変えれば可能です、後述のURLにその方法が記載されています)

今回紹介したのは単純な逐次処理ですが、複数の非同期処理が全て終了したあとに実行する.all()や、どれか1つ終了したあとに実行する.race()など色々なパターンが存在するので、Promiseを詳しく学びたいという方は下記のページがを参考にしてください。
http://azu.github.io/promises-book/
そのほかQiitaにも他の方が数多く解説記事を投稿しています。

Async / Await の紹介

Promiseだけだと実装が難しい場合などに便利なのがAsynx / Awaitです。

async_await.js
const sleep = (n) => {
  return new Promise(resolve => setTimeout(() => {
    console.log(n);
    resolve()
  }, 1000))
}

(async () => {
  for (i of [1,2,3]) {
    await sleep(i);
  }
})()
結果
1    #1秒後
2    #さらに1秒後
3    #さらに1秒後

sleep()の部分がPromiseを紹介したときのコードとほぼ変化がないのが分かるかと思います。
ちなみにAsync / Awaitを使う場合は[].forEach()が使えません、今回のコードではfor (i of [1,2,3]){ }で代用しています。

Asyncで囲んだ範囲でAwaitが使用できます。
先頭にawaitを指定して関数を実行することにより、関数内のPromiseresolve()を返した時に次の処理が実行されるようになります。

forで囲んでしまいましたが下記のコードと同等です。

(async () => {
  await sleep(1);
  await sleep(2); // 1秒後に実行される
  await sleep(3); // さらに1秒後に実行される
})()

Async / Awaitを使うことによってPromiseのハードルが低くなり扱いやすくなると思うので、Promiseって難しそう、苦手という方にこそ先にこんなのもあると知ってもらいたいです。

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