Promiseのthenが素敵
javascriptではes2015からPromise
が使えるようになります。Promise
で非同期処理を包むことで、非同期処理が終わったタイミングで次の処理を開始できて、コールバック地獄をなくす、等と言われていたりします。
詳しい使い方は検索するとたくさん出てくるので割愛させていただいて、ちょっと気になったことを書いていきます。
以下、サーバへ非同期で通信し、json
データをもらって、表示するコードです。主な動きとしては;
- 2000ms待つ。
- サーバへ非同期なGETリクエストを送信。
- レスポンスのJSON文字列をオブジェクトに変換。
- オブジェクトの情報を加工して画面に描画。
です。
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.parse
やrenderHoges
などの同期処理をチェインできることです。
つまり明確に非同期な処理だけPromise
で書けばよく、チェインさせたいがために同期処理のPromise
版を書く必要がないということです。
感想
何当たり前のこと言ってんの?と思われるかもしれないですね。
困ったのは、Promise
から値を取り出す方法はあるのだろうか?、ということです。それを必要としている時点で処理の設計を間違えているのだろうか?とりあえず、外側で宣言した変数に再代入させる方法は上手くいきませんでした。redux
でサーバとやりとりする際にaction creator
の関数の中にPromise
を使った非同期通信を書いた時に、レスポンスの中身が取り出せない。。。