JavaScript: 5分でわかるPromiseの基礎(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

JavaScript: 5分でわかるPromiseの基礎(翻訳)

JavaScriptのPromiseをわかりやすく解説しました。Promiseの基本を5分で学びましょう。

この記事で学べること

本チュートリアルでは、JavaScriptの「Promise」の基礎を学びます。Promiseのすべてを網羅的に説明するものではありませんが、Promiseを理解してコードで使い始めるのに必要な知識を固めることができます。

Promiseが必要になるとき

Promiseを使うと、(コールバックのように)特定のコードの実行完了を待ってから次のコード片を実行できるようになります。

Promiseが重要な理由は何でしょうか。あるWebサイトがAPIからデータを読み込んで処理し、データを整形してからユーザーに表示するところを考えてみましょう。APIから情報を取得する前にデータの処理と整形を行おうとすれば、エラーか空白ページのどちらかが表示されておしまいです。Promiseを使うと、API呼び出しが成功するまでAPIデータが処理されたり整形されたりしないようにできます。

Promiseとは何か

JavaScriptのPromiseは、同期操作の最終的な結果を表す、一種のプレースホルダと考えてください。本質的にこのプレースホルダは、コールバックをアタッチできる1つのオブジェクトです。

Promiseは、以下の3つのステートの1つを取ります。

  • pending: 非同期操作が完了していない
  • fulfilled: 操作が完了し、Promiseが値を1つ持つ
  • rejected : 操作がエラーまたは失敗で終了した

pending状態でないPromiseは安定しています。いったん安定したPromiseのステートはずっとそのままになり、他のステートに移行することはできません。

Promiseを使う

Promiseを使う場合、関数から返された既成のPromiseを使うことがほとんどですが、関数のコンストラクタからPromiseを作ることもできます。

シンプルなPromiseは以下のような感じになります。

runFunction().then(successFunc, failureFunc);

上のコード例では、最初にrunFunction()を実行しています。runFunction()はPromiseを1つ返すので、Promiseが安定した場合にのみsuccessFunc関数かfailureFunc関数のいずれかを実行できるようになります。PromiseがfulfilledになるとsucessFunc関数が呼ばれ、Promiseが失敗するとfailureFunc関数が呼ばれます。

Promiseの例

次は独自のPromiseを作成するコード例です。読んですぐわからなくても問題ありません。

function delay(t){
  return new Promise(function(resolve){
    return setTimeout(resolve, t)
  });
}
function logHi(){
  console.log('hi');
}
delay(2000).then(logHi);

このコードにはdelay()関数とlogHi()関数という2つの関数があります。logHi()関数は単にコンソールに'hi'と出力します。delay()関数はもう少し複雑で、指定のタイムフレームを経過した後で解決するPromiseを1つ返します。

then()メソッドを使って、最終的にfulfilledまたはrejectedのどちらかの値を受け取るコールバックを登録します。

以上を念頭に置いてdelay(2000).then(logHi)を呼び、2000ms(=2秒)という値をdelay関数に渡します。2秒経過するとPromiseが解決し、その場合に限ってlogHi関数が呼ばれます。

Google Chrome Developer Toolsを開いてこのコード例を入力することでお試しいただけます。

Promiseのチェイン

Promiseの主なメリットのひとつは、いくつもの非同期操作をチェインできることです。つまり、最初の操作が成功した場合に限って次の操作を開始するように指定できるということです。これをPromiseチェインと呼びます。以下の例をご覧ください。

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 2000);

}).then((result) => {
  alert(result);
  return result + 2;
}).then((result) => {
  alert(result);
  return result + 2;
}).then((result) => {
  alert(result);
  return result + 2;
});

最初のPromiseは、2000ms経過すると解決して値1を返します。解決後にthen()ハンドラが呼び出され、アラートボックスに値1が表示されます。最後に値が2に足され、新しい値3が返されます。この値が次のthen()ハンドラに渡され、この処理を繰り返します。

見てのとおり実地のコード例ではありませんが、Promiseが互いにチェインする様子がここに示されています。これは、JavaScriptで外部リソースを読み込む場合や処理前にAPIデータの到着を待つといった特定のタスクで非常に役立ちます。

エラーハンドリング

ここまでに扱ったPromiseは、どれも「解決済み」のものばかりでしたが、ここからは趣向を変えます。.catch()を使うと、Promiseチェインのエラーをすべてキャッチできます。次のコード例で.catch()の動作をご覧ください。

// ....
})
.catch((e) => {
  console.log('error: ', e)
}

上は.catch()のシンプルなコード例です。これは、返されたエラーメッセージをコンソールにログ出力します。先のコード例にエラーハンドリングを追加してみましょう。

以下のコード例は先ほどのものと2箇所しか違っていません。2番目の.then()の後ろにエラーとエラーメッセージを追加しました。また、チェインの末尾に.catch()も追加してあります。このコードを実行するとどうなるでしょうか。

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 2000);

}).then((result) => {
  alert(result);
  return result + 2;
}).then((result) => {
  throw new Error('FAILED HERE');
  alert(result);
  return result + 2;
}).then((result) => {
  alert(result);
  return result + 2;
}).catch((e) => {
  console.log('error: ', e)
});

結果は次のとおりです。

  • 2秒経過するとPromiseが値1で解決する
  • この値が最初の.thenに渡されてアラートダイアログが画面に表示される。2が足され、新しい値3が2番目の.then()に渡される。
  • 新しいErrorがスローされる。実行は直ちに停止してPromiseはrejectedステートで解決する。
  • .catch()はエラー値を受け取って画面にログを出力する。コンソールには次のように表示されます。

最後に

お読みいただきありがとうございました。Promiseのもっと詳しい情報についてはこちらこちらこちらをご覧ください。本記事がPromise導入のよいきっかけとなればと願っています。最終的にWeb開発を学ぶ用意のある方は、6か月でフルスタックWeb開発を学ぶ究極ガイドをぜひチェックしてみてください。

私はWeb開発記事を週に4本公開しています。毎週配信しているメーリングリストを購読したい方はフォームから登録いただくか、Twitterで私をフォローして下さい。

本記事が皆さまのお役に立ちましたら、元記事の下にある[👏]ボタンを数回クリックしてサポートをお願いします。⬇⬇

関連記事

JavaScriptの正規表現のコンセプトを理解する(翻訳)

JavaScriptスタイルガイド 1〜8: 型、参照、オブジェクト、配列、関数ほか (翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ