HOWTO · JavaScript

JavaScript でプロミスの解決を待つ

この記事では、JavaScript でコードの次の部分を実行する前に、promise が解決されるのを待つ方法を見ていきます。

このページの内容

ECMA スクリプト(ES6)バージョンでは、JavaScript プログラミング言語の最新機能のほとんどが導入されました。このバージョンでは、JavaScript の最も著名で広く使用されている機能の 1つである、promise と呼ばれるこの言語の機能も導入されました。

ご存知のように、JavaScript 言語はシングルスレッド言語であり、特定の順序で 1つのタスクしか実行できないことを意味します。場合によっては、これにより問題が発生する可能性があります。

たとえば、3 秒後に実行される setTimeout() 関数を使用した場合、JavaScript コンパイラは 3 秒待機しません。以下に示すように、コードの次の部分の実行を開始します。

function abc() {
  console.log('a');
  setTimeout(() => {
    console.log('b');
  }, 3000)
  console.log('c');
}
abc();

出力:

a
c
b

ここで、b は c の前に出力されている必要がありますが、そうではありません。そのため、これを克服するために、JavaScript で promise が導入されました。これは、非同期タスクの実行に役立ちます。

promise がどのように機能するかを見て、promise がバックグラウンドで解決されるまで待ちましょう。また、この記事で学習する概念のほとんどは、JavaScript ES6 バージョン以降でサポートされており、IE などの古いブラウザーでは機能しない可能性があります。

JavaScript の promise は何ですか

データベースリクエストや API リクエストなどのリクエストを実行するたびに、サーバーからデータを取得するのに時間がかかる場合があります。多くのリクエストが同時に実行される本番環境では、このような操作にどれだけの時間がかかるかはわかりません。

JavaScript の Promise を使用すると、そのような操作またはタスクの実行が完了するのを待つことができ、タスクが実行されたかどうかに基づいて、さらにアクションを実行できます。

promise を使用するには、new キーワードを使用して Promise クラスオブジェクトを作成する必要があります。Promise は、解決と拒否の 2つの引数を取ります。

resolve() メソッドは、値で解決される promise オブジェクトを返します。promise の実行中にエラーが発生した場合、reject メソッドはエラーを返します。

Promise は async および await キーワードを使用します。これらのキーワードは、promise を実装する際に重要かつ必要です。

これらについては、この記事の後半で詳しく説明します。

JavaScript での promise の段階

Promises に例えると、あなたとあなたの友人は、日曜日に一緒に映画を見に行くことをお互いに promise していると言うことができます。そして、その金曜日と約束が今日行われたと仮定します。

日曜日はまだ来ていないので、技術的には約束は保留中であると言えます。日曜日に友達に会うと約束は果たされ、映画を見に行かずに約束を破ると約束は拒否されます。

JavaScript の Promise は 3 段階で実行され、次のようになります。

javascript での Promise のステージ

  • Pending:Promise が実行されているとき、それは保留中の段階にあると言われます。
  • Fulfilled:Promise が正常に実行を完了すると、Promise は解決され、実行された操作の値を返します。これは、promise が成就した段階にあると言われているところです。
  • Rejected:Promise の実行中に失敗すると、Promise は拒否され、エラーメッセージが返されます。これは、promise が拒否された段階にあると言われているところです。

JavaScript で async および await キーワードを使用して Promise を実装する

async キーワードと await キーワードは、promise を実装する際に連携して機能します。

async キーワードは、実行に時間がかかると思われる関数で使用できます。これにより、それらは非同期に機能します。

このキーワードは、JavaScript エンジンに、その関数内のコードの一部が実行に時間がかかる可能性があり、実行が完了するまで待つ必要があることを通知します。

その関数内のコードのどの部分の実行に時間がかかるかを指定する必要があります。ここで await キーワードを使用します。

したがって、その関数内で await キーワードを使用する場合は常に、JavaScript エンジンはその部分が完全に実行されるまで待機します。実行が成功した場合、履行された Promise が返されるか、Promise が拒否されます。

次の例はこれを示しています。

ここに、myPromise という関数があります。この関数内に、解決または拒否された Promise を作成しました。

この関数の役割は、API から JSON データをフェッチすることです。API にデータをリクエストしているため、Promise の実行に時間がかかる可能性があるため、await を使用して Promise が解決するのを待ちました。

Promise を返す前に await を使用するため、myPromise を async として機能させる必要があります。

使用した API は、JSONPlaceholderWeb サイトの無料 API です。この API を使用して、投稿データを取得します。

fetch() 関数を使用して、この API からデータをフェッチできます。この関数がデータをフェッチした後、then() 関数を使用して次に何をしたいかを指定する必要があります。

fetch() 関数から then() 関数にパラメータとしてデータを返すだけです。パラメータの名前は何でもかまいません。パラメータ名として response を指定しました。

最後に、response.json() 関数を使用して結果を JSON 形式に変換することにより、Promise の解決を返します。

async function myPromise() {
  return await new Promise((resolve, reject) => {
    fetch('https://jsonplaceholder.typicode.com/posts')
        .then(response => {
          resolve(response.json());
        })
        .catch(error => {
          reject(error);
        });
  })
}

API からデータをフェッチしているときにエラーが発生した場合、それは catch() 関数によって処理されます。この関数は、reject() 関数を使用してエラーを返します。

Promise が解決されたら、then() 関数を使用して返されるデータを使用して、次にやりたいことを何でも行うことができます。複数の then() 関数を使用できます。これらの関数は、順番に実行されます。

また、エラーをキャッチしたい場合は、catch() 関数を使用できます。

myPromise().then(result => {
  result.forEach(element => {
    var heading = document.createElement('h2');
    heading.innerHTML = element.title;
    document.body.appendChild(heading);
  });
});

出力:

タイトルのリストを約束します

myPromise() 関数が解決された promise を返した後、then() 関数を使用して投稿のタイトルを取得し、HTML ドキュメントに表示します。

ここでは、h2 見出しタグを作成し、postsAPI から受け取った結果データ内に存在するタイトルを HTML ドキュメントの body に追加しています。