ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Promiseのthenが素敵

 javascriptではes2015からPromiseが使えるようになります。Promiseで非同期処理を包むことで、非同期処理が終わったタイミングで次の処理を開始できて、コールバック地獄をなくす、等と言われていたりします。

 詳しい使い方は検索するとたくさん出てくるので割愛させていただいて、ちょっと気になったことを書いていきます。

 以下、サーバへ非同期で通信し、jsonデータをもらって、表示するコードです。主な動きとしては;

  1. 2000ms待つ。
  2. サーバへ非同期なGETリクエストを送信。
  3. レスポンスのJSON文字列をオブジェクトに変換。
  4. オブジェクトの情報を加工して画面に描画。

です。

app/index.js

const wait = ms => {
  return new Promise((resolve, reject) => {
    console.log(`wait ${ms}ms...`);
    setInterval(_ => {
      resolve('OK!');
    }, ms)
  });
}

const fetchData = url => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);

    xhr.onload = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        resolve(xhr.response);
        return;
      }

      reject(new Error(xhr.statusText));
    };

    xhr.onerror = () => {
      reject(new Error(xhr.statusText));
    };

    xhr.send(null);
  });
};

const renderHoges = data => {
  const root = document.getElementById('root');
  root.innerHTML = '';

  data.forEach(item => {
    let node = document.createElement('div');
    node.innerText = `${item.id}: ${item.hoge}`;
    root.appendChild(node);
  });

  return data.length;
};

wait(2000)
.then(_ => fetchData('/api/hoges'))
.then(JSON.parse)
.then(renderHoges)
.then(length => console.log(`${length} hoges rendered!`))
.catch(error => console.error(error));

app/static/index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Promise</title>
</head>
<body>
  <div id="root">loading...</div>
  <script type="text/javascript" src="bundle.js"></script>
</body>
</html>

サーバ側はここから見れます。

 嬉しいなと思ったのは、thenを使うことで、もともとPromiseを考慮していないJSON.parserenderHogesなどの同期処理をチェインできることです。

 つまり明確に非同期な処理だけPromiseで書けばよく、チェインさせたいがために同期処理のPromise版を書く必要がないということです。

感想

 何当たり前のこと言ってんの?と思われるかもしれないですね。

 困ったのは、Promiseから値を取り出す方法はあるのだろうか?、ということです。それを必要としている時点で処理の設計を間違えているのだろうか?とりあえず、外側で宣言した変数に再代入させる方法は上手くいきませんでした。reduxでサーバとやりとりする際にaction creatorの関数の中にPromiseを使った非同期通信を書いた時に、レスポンスの中身が取り出せない。。。