記事ページを表示中

Javascript|非同期処理Promiseの使いかた

記事No.59

更新日時2023年02月17日

クライアントからウェブサーバーにリクエストを送る際、リクエストの間隔が短すぎるとウェブサーバーに負荷がかかり過ぎて処理が追いつかない事があります。

今回目指したのは、クライアントから複数のリクエストを一度に送るのではなく、1つのリクエストを送って、レスポンスが返ってきたら、次のリクエストを送る。といった動作です。

クライアント側のリクエストは、JavaScriptで操作しますが、JavaScriptは非同期で動く為、1つのリクエストを送って、レスポンスが返ってきたら、次のリクエストを送る。といった動きをさせるには、Promiseの理解が必要でした。

Promiseを使用する事で、プログラムを順番通りに実行する事ができます。

Promiseと同じような動きをするものに、async/awaitがありますが、今回は、Promiseの動きを理解する事に焦点をあてます。

Promiseについて

Promise…ES2015で追加

Promiseには3つの状態があります。

pending:非同期処理の実行中の状態

fulfilled:非同期処理が正常終了した状態

rejected:非同期処理が異常終了した状態

//Promiseの基礎構文
//new演算子を使用してPromiseオブジェクトをインスタンス化する
//コールバック関数(関数の引数に指定する別の関数)にfunctionを指定
new Promise(function (resolve, reject){
  //非同期処理
})
//>>Promise {<pending>}

Promise()内のコールバック関数に、resolve,rejectを指定。

resolve():非同期処理が正常終了した事を知らせるメソッド。returnの代わりに、resolve()を使用する事で、非同期関数が正常終了した事を知らせる。

reject():非同期処理が異常終了した事を知らせるメソッド。returnの代わりに、reject()を使用する事で、非同期関数が異常終了した事を知らせる。

上のプログラムを実行すると、

Promise{<pending>}

が返ってきます。pendingは、非同期処理が実行中であるという意味です。

Promiseの中で非同期処理を呼び出す場合は必ず、非同期処理が終了した事を伝える為に、resolve()もしくはreject()を実行します。

終了した事が伝わらないと、pendingの状態が続きます。

以下のプログラムでは、try…catch文を使用して、処理が成功した場合は、resolve()を使用し、失敗した場合は、reject()を使用するようにしています。

new Promise(function (resolve, reject){
  try {
    //非同期処理
    //正常終了した事を通知するresolveを使用
    resolve();
  } catch (e) {
  //異常終了時の処理
  //異常終了した事を通知するrejectを使用
  reject();
  }
})
//非同期処理が正常終了した状態を表すfulfilledが表示される
//>>Promise {<fulfilled>: undefined}

ここまでで、Promiseの基本的な使いかたが分かりました。

では、どのようにして非同期処理の処理順序を管理すれば良いのでしょうか。

Promiseに限らず、JavaScriptの非同期処理は、その戻り値に対してthenメソッドとcatchメソッドが利用できます。

・then():非同期処理が正常終了した際に呼ばれるメソッド

・catch():非同期処理が異常終了した際に呼ばれるメソッド

つまり、

resolve()は非同期処理が正常終了した事を伝えるメソッドで、then()は正常終了した場合に呼ばれるメソッドなので、1番目の処理の最後にresolve()を実行すれば、2番目の処理としてthen()が実行されます。

こうする事で、JavaScriptの処理に順番を付ける事ができます。

以下、サンプルコード

function asyncFunction() {
  return new Promise((resolve, reject) => {
    try {
      setTimeout(() => {
        //処理内容
        console.log("非同期処理")
        resolve();
      }, 1000)
    } catch (e) {
        //異常終了時の処理
        reject();
    }
  })
}
 
asyncFunction().then(() => {
  console.log("resolve後の処理");
}).catch(e => {
  console.log("reject後の処理");
})
 
//>>Promise {<pending>}
//>>非同期処理
//>>resolve後の処理

順番を付けてメソッドを実行する方法が分かりました。

次は、1番目のメソッドで取得した値を、2番目のメソッドで使用する方法です。

以下、サンプルコード

function asyncFunction() {
  return new Promise((resolve, reject) => {
    try {
      setTimeout(() => {
        console.log("非同期処理")
        const num = 1
        resolve(num);
      }, 1000)
    } catch (e) {
      //異常終了時の処理
      reject(e);
    }
  })
}
 
asyncFunction().then((num) => {
    console.log(`引数で受け取った値:${num}`);
}).catch(e => {
    console.log(`引数で受け取った値:${e}`);
})
 
//>>Promise {<pending>}
//>>非同期処理
//>>引数で受け取った値:1

このようにして1番目のメソッドで取得した値を、2番目のメソッドに渡します。

ループ処理をする場合は、以下のようになります。

new Promise(function(res, rej) {
  //loop関数を作成
  function loop(i) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log(i);
        //成功して終了した事を伝える
        resolve(i+1);
      }, 100);
    })
    //処理が成功したら実行される
    .then(function(count) {
      if (count > 10) {
        //成功して終了した事を伝える
        res();
      } else {
        //countが10未満の場合loop関数を実行する
        loop(count);
      }
    });
  }
  loop(0);
//処理が成功したら実行される
}).then(function() {
  console.log("Finish");
})

コメントフォーム

著者情報

名前:スカーレット
2010年からWEBサイトやWEBアプリを作成しています。最初は趣味でブログを書いていましたがSEOを勉強するのが楽しくなり、そのままブロガーとして独立しました。その後、記事を書くだけでは物足りなくなり自分でWEBアプリの作成をスタート。現在はブロガー兼プログラマーとして活動しています。このWEBアプリ(ブロトーク)もDjangoで自作しました。ブロトークはブログとSNSを合体させたようなWEBアプリです。ブログを読んで気づいた事や感想などあれば、気軽にメッセージを送って頂ければと思います。WEB技術を一緒に勉強していけたらと思います。

関連記事