ES6 Promiseの使い方の詳細な説明

ES6 Promiseの使い方の詳細な説明

約束とは何ですか?

Promise は非同期プログラミングのソリューションです。実際には、all、reject、resolve などのメソッドを持つコンストラクターです。そのプロトタイプには、then や catch などのメソッドがあります。 (追記: プロトタイプとは何か: https://www.jb51.net/article/231967.htm)

Promise オブジェクトには次の 2 つの特性があります。

  • (1)物体の状態は外界の影響を受けない。 Promise オブジェクトは非同期操作を表し、保留中 (進行中)、実行済み (成功)、拒否済み (失敗) の 3 つの状態があります。非同期操作の結果のみが現在の状態を決定し、他の操作ではこの状態を変更できません。これは、英語で「約束」を意味する Promise という名前の由来でもあり、他の手段では変更できないことを示しています。
  • (2)一度状態が変化すると、再び変化することはなく、いつでも結果が得られる。 Promise オブジェクトの状態が変化する可能性は、保留から完了へ、または保留から拒否へという 2 つだけです。この2つの状況が発生している限り、状態は固定され、それ以上変化しません。結果は常に維持されます。このとき、解決済みと呼ばれます。変更がすでに発生している場合は、Promise オブジェクトにコールバック関数を追加すると、すぐに結果が得られます。これはイベントとは全く違います。イベントは聞き逃したら何も得られないという特性があります。

新しい約束を作りましょう

p = new Promise(function(resolve, reject){ とする
		//非同期操作を実行する setTimeout(function(){
			console.log('実行が完了しました Promise');
			解決('返されるデータは、インターフェースの戻りデータなど、任意のデータにすることができます');
		}, 2000);
	});

ページを更新すると、コンソールが直接印刷されることがわかります。

実行プロセスは、非同期操作、つまり setTimeout が実行され、2 秒後に「実行が完了しました」が出力され、resolve メソッドが呼び出されます。

知らせ!新しいオブジェクトを作成しただけで、呼び出しは行っていません。渡した関数は実行されました。これは注意が必要な詳細です。したがって、Promise を使用する場合は、通常、次のように関数内にラップし、必要に応じて関数を実行します。

<div onClick={promiseClick}>非同期リクエストを開始</div>
 
const promiseClick = () => {
	 console.log('クリックメソッドが呼び出されました')
	 p = new Promise(function(resolve, reject){ とする
		//非同期操作を実行する setTimeout(function(){
				console.log('実行が完了しました Promise');
				解決('返されるデータは、インターフェースの戻りデータなど、任意のデータにすることができます');
			}, 2000);
		});
        戻るp
	}

ページを更新しても反応がないが、クリックするとコンソールに印刷される

関数内に配置すると、呼び出されたときにのみ実行されます。

それでは、2つの問題を解決してみましょう。

  • 1. なぜ関数内に配置する必要があるのですか?
  • 2. 解決とは何か?

パッケージ化された関数の最後に、Promise オブジェクトを返します。つまり、この関数を実行することで Promise オブジェクトを取得します。次に、Promise オブジェクトで then メソッドと catch メソッドを使用できます。これが Promise の威力です。次のコードを参照してください。

promiseClick().then(function(data){
    コンソールにログ出力します。
    //渡されたデータを使用して、後で他の操作を行うことができます//......
});

このコンソール出力

まず、メソッドが呼び出されてpromiseが実行され、最後にpromiseのthenメソッドが実行されます。thenメソッドは、resolveによって返されるデータを受け入れるパラメータを受け入れる関数です。これは、「返されるデータは、インターフェースの戻りデータなど、任意のデータにすることができます」と出力します。

この時点で、then の関数は、promiseClick の非同期タスクが完了した後に実行できる通常のコールバック関数と同じであることがわかったはずです。これが Promise の役割です。簡単に言うと、本来のコールバックの記述方法を切り離し、非同期処理の実行後にチェーン呼び出し方式でコールバック関数を実行できるというものです。

これはコールバック関数を記述するのと何ら変わらないと思うかもしれません。では、コールバックが複数層ある場合はどうなるのでしょうか?コールバックも非同期操作であり、実行後に対応するコールバック関数が必要な場合はどうなりますか?別の callback2 を定義してそれを callback に渡すことはできません。 Promise の利点は、then メソッドで Promise オブジェクトを記述して返し、then を呼び出し続けてコールバック操作を実行できることです。

つまり、本質は次のとおりです。Promise は、コールバックのレイヤーの記述を簡素化することしかできませんが、実際には、Promise の本質は「状態」であり、状態を維持して渡す方法を使用して、コールバック関数を適時に呼び出すことができます。コールバック関数を渡すよりもはるかにシンプルで柔軟性があります。したがって、Promise を使用する正しいシナリオは次のようになります。

プロミスクリック()
.then(関数(データ){
    コンソールにログ出力します。
    runAsync2() を返します。
})
.then(関数(データ){
    コンソールにログ出力します。
    runAsync3() を返します。
})
.then(関数(データ){
    コンソールにログ出力します。
});

このように、各非同期コールバックの内容を2秒ごとに順番に出力し、runAsync2でresolveに渡されたデータを次のthenメソッドで取得することができます。

(追記: ここで複数回実行される理由は、この使用法を研究していたときに、React デモで実行していたためです。ページ上の複数の要素が変更されたため、ページが複数回レンダリングされました。通常のページが 1 回だけレンダリングされる場合は、実行も 1 回だけです。)

拒否の使用法

上記はpromiseのresolveの使い方の説明です。resolveはpromiseが成功したときのコールバックに相当します。promiseの状態を次のように変更します。

fullfiled の場合、reject は失敗したときのコールバックです。promise の状態を declined に変更し、then でそれをキャプチャして、「失敗」状況のコールバックを実行できるようにします。

関数promiseClick(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
 
	promiseClick().then() を実行します。
		関数(データ){
			console.log('コールバックが成功しました');
			console.log('成功したコールバックによって受け入れられた値:',data);
		}, 
		関数(理由){
			console.log('失敗したコールバックを拒否しました');
			console.log('実行コールバックが失敗の理由をスローします:',reason);
		}
	);

実行結果:

(追記: これも複数回実行されるため、出力も複数回になります。複数回実行される理由は前回と同じです)

上記のコードでは、promiseClick メソッドを呼び出して実行し、2 秒後に乱数を取得します。10 未満の場合、成功とみなし、resolve を呼び出して Promise の状態を fullfiled に変更します。それ以外の場合は「失敗」とみなし、reject を呼び出して失敗の理由としてパラメータを渡します。ステータスを拒否に変更します

promiseClick を実行し、then に 2 つのパラメータを渡します。これらの 2 つのパラメータは 2 つの関数です。then メソッドは 2 つのパラメータを受け入れることができ、最初のパラメータは解決コールバックに対応し、2 番目のパラメータは拒否コールバックに対応します。 (つまり、thenメソッドは成功用と失敗用の2つのコールバックを受け入れ、コールバック関数で成功データと失敗理由を取得できます)したがって、成功と失敗によって渡されたデータをそれぞれ取得でき、上記の実行結果が得られます。

キャッチの使い方

Promise オブジェクトの then メソッドと並行して実行されるメソッドは catch です。try catch と同様に、catch は例外をキャッチするために使用されます。これは、次のように then メソッドによって受け入れられた拒否された 2 番目のパラメータのコールバックと同じです。

関数promiseClick(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
 
	promiseClick().then() を実行します。
		関数(データ){
			console.log('コールバックが成功しました');
			console.log('成功したコールバックによって受け入れられた値:',data);
		}
	)
	.catch(関数(理由, データ){
		console.log('拒否された失敗のコールバックをキャッチ');
		console.log('catch はコールバックの実行に失敗しました。失敗の理由をスローします:',reason);
	});

実行結果:

効果は then の 2 番目のパラメータに記述するのと同じです。値が 10 より大きい場合、失敗したコールバックの理由を出力します。ただし、別の機能もあります。resolve コールバック (つまり、上記の then の最初のパラメーター) を実行するときに例外がスローされた場合 (コード エラー)、エラーを報告して JS をフリーズさせるのではなく、この catch メソッドに入ります。次のように:

関数promiseClick(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
 
	promiseClick().then() を実行します。
		関数(データ){
			console.log('コールバックが成功しました');
			console.log('成功したコールバックによって受け入れられた値:',data);
			コンソールログ(データなし);
		}
	)
	.catch(関数(理由, データ){
		console.log('拒否された失敗のコールバックをキャッチ');
		console.log('catch はコールバックの実行に失敗しました。失敗の理由をスローします:',reason);
	});

実行結果:

解決コールバックでは、console.log(noData); を実行しますが、変数 noData は定義されていません。 Promise を使用しない場合、コードはこの時点で実行されたときにコンソールにエラーを報告し、それ以上実行されません。しかし、ここでは、上の図に示す結果が得られます。つまり、catch メソッドに入り、エラーの原因を reason パラメータに渡します。コードにエラーがあっても、エラーは報告されません。

すべての使用法

then と同じレベルにある別のメソッドである all メソッドは、非同期操作を並列に実行する機能を提供し、すべての非同期操作が実行され、実行結果が成功した場合にのみコールバックを実行します。

上記のメソッドを2回コピーし、次のようにpromiseClick3()、promiseClick2()、promiseClick1()という名前に変更します。

関数promiseClick1(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
	   関数promiseClick2(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
	   関数promiseClick3(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('生成された乱数の値:', num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('数値が 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
 
	約束
		.all([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(関数(結果){
			console.log(結果);
		});

Promise.all は実行に使用されます。all は配列パラメータを受け取ります。このパラメータ セットは、非同期操作を実行するために必要なすべてのメソッドです。その中の値は最終的に Promise オブジェクトを返すものとみなされます。この方法では、3 つの非同期操作が並行して実行され、すべてが実行されるまで then 操作は実行されません。では、3 つの非同期操作によって返されたデータはどこに行くのでしょうか?すべてはthenにあります。allはすべての非同期操作の結果を配列に入れてthenに渡します。次に、thenメソッドの成功したコールバックが実行され、結果を受け取ります。結果は次のとおりです。(結果は個別に実行することで得られます。allは3つの関数を均一に実行し、値を配列に格納してthenに返してコールバック出力します):

このように、 all を使用して複数の非同期操作を並行して実行し、返されたすべてのデータを 1 つのコールバックで処理することができます。たとえば、ページをレンダリングする前にすべてのデータを事前に準備する必要がある場合、 all を使用して複数の非同期操作を実行し、レンダリング前にすべてのデータを処理することができます。

レースの使用

all は、then メソッドを実行する前にすべての非同期操作が完了するまで待機することを意味します。一方、race メソッドはその逆です。操作が先に完了した場合、コールバックが先に実行されます。最初に実行されるものは、レースのコールバックが成功したか失敗したかに関係なく、レースのコールバックに再度入ることはありません。

上記の方法の遅延をそれぞれ234秒に変更します。

 
関数promiseClick1(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('2s 乱数生成値:',num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('2 の数字は 10 には大きすぎるため、コールバックは失敗します');
				}
			}, 2000);
		   })
		   戻るp
	   }
	   関数promiseClick2(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('3s 乱数生成値:',num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('3s の数字は 10 には大きすぎるため、コールバックは失敗します');
				}
			}, 3000);
		   })
		   戻るp
	   }
	   関数promiseClick3(){
		p = new Promise(function(resolve, reject){ とする
			setTimeout(関数(){
				var num = Math.ceil(Math.random()*20); // 1 から 10 までの乱数を生成します console.log('4s 乱数生成値:',num)
				if(数値<=10){
					解決(数値);
				}
				それ以外{
					拒否('4s の数値は 10 より大きすぎるため、コールバックは失敗します');
				}
			}, 4000);
		   })
		   戻るp
	   }
 
	約束
		.race([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(関数(結果){
			console.log('成功',結果);
		},関数(理由){
			console.log('失敗',理由);
		});

2 秒後に promiseClick1 が実行されると、then のコールバックに入ります。then のコールバックの実行が開始されると、promiseClick2() と promiseClick3() は停止せず、まだ実行中です。その後さらに 3 秒後にそれぞれの値が出力されますが、レースのコールバックは再度入力されません。図に示すように、2s が 10 を生成し、race の成功コールバックに入った後、残りの関数は引き続き実行されますが、再び race のコールバックに入ることはありません。2s は 16 を生成し、race の失敗コールバックに入り、残りは引き続き実行されますが、再び race のコールバックに入ることはありません。

たとえば、race を使用すると、リクエストが 10 秒以内に成功した場合に then メソッドを実行できます。リクエストが 10 秒以内に成功しなかった場合は、reject コールバックに入り、別の操作を実行します。

補足: (race の使用を実装する方法を尋ねられたので、たとえば、リクエストが 10 秒以内に成功した場合は then メソッドが使用されます。リクエストが 10 秒以内に成功しなかった場合は、reject コールバックに入り、別の操作を実行します。この質問では、表現に問題があると思うので、例を挙げてみましょう)

 //テーブルデータを要求する関数 requestTableList(){
        var p = new Promise((resolve, deny) => {
               //バックエンドにアクセスしてデータをリクエストします。これは、ajax、axios、またはfetchのいずれかになります。 
                解決する(res);
        });
        p を返します。
    }
  //遅延関数。リクエストを10秒間待つために使用されます。
      関数タイムアウト(){
          var p = new Promise((resolve, deny) => {
              タイムアウトを設定する(() => {
                  拒否('リクエストタイムアウト');
              }, 10000);
          });
          p を返します。
      }
      Promise.race([requestTableList(), timeout()]).then((データ) => {
        //成功したコールバック処理を実行します console.log(data);
      }).catch((エラー) => {
        // 失敗コールバック処理 console.log(err);
      });

インターフェースデータを要求し、要求が10秒以内に完了した場合はデータを表示し、要求が10秒以内に完了しなかった場合は要求が失敗したことを通知します。

ここでは 2 つの約束が定義されています。1 つはデータを要求する約束、もう 1 つは 10 秒の時間を計る約束です。2 つの約束は、競争に投入されます。データ要求が先に完了した場合、要求されたデータを表示するために .then 成功コールバックに直接入ります。タイミングが先に完了した場合、つまり 10 秒後にデータ要求が成功しなかった場合、最初に競争失敗コールバックに入り、ユーザーにデータ要求が失敗したことを通知して .catch コールバックに入ります。(ps: または拒否失敗コールバックに入ります。.then に拒否コールバックがない場合、失敗コールバックは直接 .catch に入ります)

これで、ES6 Promise の詳細な使用法に関するこの記事は終了です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援して頂ければ幸いです。

以下もご興味があるかもしれません:
  • ES6 学習チュートリアル: Promise の使用方法の詳細な説明
  • es6 の Promise オブジェクトの基本機能と使用例の分析
  • ES6 Promise オブジェクトの概念と使用例
  • ES6 Promiseオブジェクトの意味と基本的な使い方の分析
  • ES6 Promiseの使い方の詳細な説明

<<:  HTML 描画ユーザー登録ページ

>>:  ウェブページの読み込み速度を上げる簡単なヒント

推薦する

シェルスクリプトによるDockerコンテナの起動順序の制御の詳細な説明

1. 遭遇した問題分散プロジェクトの展開プロセスでは、サーバーの再起動後にアプリケーション(データベ...

MySQL における in と exists の使い方と違いの紹介

まずコードを書いて (int i=0;i<1000;i++){ (int j=0;j<5...

入力テキストボックスの長さをコンテンツに応じて変更する方法

初め:コードをコピーコードは次のとおりです。 <input type="text&q...

MySQLで一意のサーバーIDを生成する方法

序文MySQL では、server-id を使用してデータベース インスタンスを一意に識別し、それを...

JavaScript実行メカニズムの詳細な紹介

目次1. プロセスとスレッドの概念2. ブラウザの原則3. 同期と非同期4. 実行スタックとタスクキ...

ゲーム開発におけるサウンド処理にCocosCreatorを使用する方法

目次1. Cocos Creatorでのオーディオ再生の基本1. 基本2. 一般的な方法2. Coc...

データベースインデックスの知識ポイントの概要

目次ファーストルックインデックスインデックスの概念インデックスファイルの構成インデックスの役割SQL...

momentJs を使用してカウントダウン コンポーネントを作成する (サンプル コード)

今日はvueとmomentで作ったカウントダウンを紹介したいと思います。具体的な内容は以下のとおりで...

JavaScriptコールバック関数の詳細な理解

目次序文クイックレビュー: JavaScript 関数関数とは何ですか?関数を宣言する関数の呼び出し...

CSS3 で less のテキストの長い影を実装する

この記事では主に、CSS3 LESS で長いテキストの影を実装する方法を紹介し、皆さんと共有します。...

Vueでスケルトンスクリーンを実装する例

目次スケルトンスクリーンの使用Vueアーキテクチャスケルトンスクリーンアイデアの概要抽象コンポーネン...

Raspberry PiにDockerをインストールする方法

Raspberry Pi は ARM アーキテクチャをベースとしているため、Docker のインスト...

Nginx で Brotli 圧縮アルゴリズムを有効にする方法の例

Brotli は、Zopfli よりも 20 ~ 26% 高い圧縮率を実現できる新しいデータ形式です...

mysql トリガーの作成と使用例

目次トリガーとは何かトリガーを作成するMySQL 作成構文のキーワードの説明: 1. MySQL ト...

Mysql の主キーと一意キーの違いのまとめ

主キーとは何ですか?主キーは、テーブル内の各タプル (行) を一意に識別するテーブル内の列です。主キ...