Promise とは?未来の値のためのプレースホルダ
promise は、まだ準備できていない値の代わりとなるオブジェクトで、非同期操作の最終的な成功または失敗を表します。
promise(一部の言語では future と呼ばれます)は、後で存在する結果へのハンドルです。呼び出す callback を渡す代わりに、async 関数はただちに promise を返します。成功したときと失敗したときのハンドラを取り付けると、操作が完了した時点で promise がそれらに通知します。promise はきれいに連鎖し、async/await を支えます。
promise の状態
promise は操作が終わるまで pending で、その後、値とともに fulfilled になるかエラーとともに rejected になります。いったん settle すると、その状態は決して変わりません。then と catch で取り付けたハンドラは promise が settle したときに実行され、それがすでに起きていても実行されます。
なぜ promise は生の callback に勝るのか
- ネストする代わりに then で連鎖し、非同期のフローを平坦化します。
- エラーは連鎖を下って 1 つの catch まで伝播します。
- 合成できます。組み込みのヘルパーで、すべてを待ったり、複数を race させたりします。
- async/await が作られている基礎です。
promise と async/await
async/await は promise の糖衣です。async 関数は promise を返し、await は promise が settle するまで一時停止し、その値を返すかエラーを throw します。promise を理解することは、async/await が内部で何をするかを理解することです。
promise のよくある間違い
連鎖から promise を return しないと順序が壊れます。catch を忘れると reject が未処理のままになります。promise を作っても await しないと、その作業とエラーが黙って失われます。微妙なバグの頻繁な源です。
簡単な例
fetch(url).then(res => res.json()).catch(err => report(err)) を呼ぶと promise を返し、レスポンスが届いたときにそれをパースし、あらゆる失敗を 1 つの error handler へ回します。
CI における promise
未処理の promise の reject や await されない promise は、負荷のかかった runner で現れては消える、順序依存で flaky なテストの失敗を招きます。Latchkey は未処理の reject を追い詰める間、一時的な失敗を自動 retry できるため、1 回の間欠的な失敗が pipeline をブロックしません。
重要なポイント
- promise は、結果で fulfill するかエラーで reject する未来の値を表します。
- promise は連鎖・合成でき、生の callback のネストとエラー処理を修正します。
- async/await は promise の上に作られています。未処理の reject は flaky なテストを招きます。