JavaScript

Promiseとasync/awaitの関係

More than 1 year has passed since last update.

これは何?

async/awaitとPromiseの関係を今更だけど自分なりに理解したときのメモです。

説明

Promise

非同期処理の書き方を定めたJavaScriptとしてのルール。

  • うれしい点
    • 非同期処理の書き方が統一され可読性が向上
    • Callbackのネストを浅くすることができる

詳細は「今更だけどPromise入門」が分かりやすい。

async/await

Promiseの弱点である、多い回数のループの処理をより簡単に書くことができるようにするJavaScriptとしてのルール。
Promiseを先に理解する必要があるが覚えるととても便利。

  • うれしい点

    • あたかも同期処理のような書き方ができる為、コード量の減少、可読性の向上が期待できる
  • 覚書

    • awaitはPromiseの処理完了を待つことができるので、記述的に非同期処理をあたかも同期処理と同じように記述できる
    • awaitを関数の中に入れる場合には、その関数をasyncとして宣言する必要がある
    • Promiseと混ぜて書くことももちろん可能

詳細は「async/await 入門(JavaScript)」が分かりやすい。

XHRを書いてみる

fetch()がある現代ではその意味はゼロだけど理解するために書いてみた。

コード

実行と同時に青い丸を表示します。非同期にurlで指定したページ(例では「http://localhost/hoge.html」)を取得後、delay で指定された時間(例では「3秒」)だけ待ち、取得した内容を画面に表示するスクリプトです。

<html>
  <head>
    <title>XHRとasync/await</title>
    <style>
     .blue-circle {
       width: 100px;
       height: 100px;
       background-color:#536DFE;
       border-radius:50%;
     }
    </style>
  </head>
  <body>
    <script>
     function asyncxhr(url) {
         return new Promise( (resolve, reject) => {
             const xhr = new XMLHttpRequest();
             xhr.open('GET', url, true);
             xhr.send();
             xhr.onreadystatechange = function() {
                 if(xhr.status === 200 && xhr.readyState === 4) {
                     setTimeout( () => {
                         resolve(xhr.responseText);
                     }, 3000);
                 /* http status code: https://httpstatuses.com/ */
                 } else if(xhr.status >= 307 && xhr.readyState === 4) {
                     reject(new Error(xhr.statusText));
                 }
             }
             xhr.onerror = function() {
                 reject(new Error(xhr.statusText));
             }
         });
     }

// [ここから] 別の書き方
     async function exec00(url, msec) {
         try {
             const content = await asyncxhr(url, msec);
             console.log('[SUCCESS] ', content);
             let pre = document.createElement('pre');
             pre.innerText = content;
             document.body.append(pre);
         } catch(error) {
             console.log('[ERROR] ', error);
         }
     }

     const url = 'http://localhost/hoge.html';
     const delay = 3000;
     exec00(url, delay);
// [ここまで] 別の書き方

     let div = document.createElement('div');
     div.classList.add('blue-circle');
     document.body.append(div);
    </script>
  </body>
</html>

ちなみに別の書き方の部分は以下のように即時関数で書くことも可能です。

(async function() {
    try {
        const url = 'http://localhost/~kawai/tmp/aaa/index.html';
        const delay = 3000;
        const content = await asyncxhr(url, delay);
        console.log('[SUCCESS] ', content);
        let pre = document.createElement('pre');
        pre.innerText = content;
        document.body.append(pre);

    } catch(error) {
        console.log('[ERROR] ', error);
    }
}());

実行画面

最低3秒間の時間を待って、取得したページの内容を表示していることが分かる。

Screen Shot 2017-10-29 at 1.42.37 PM.png

まとめ

Promiseの理解がasync/awaitを使う条件ですが覚えるとコード量が減る上、可読性も上げることができるので全体的にスピードアップが期待できるのではないでしょうか?

参照したQiita