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 描画ユーザー登録ページ

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

推薦する

Vue の計算プロパティの詳細な説明

目次補間式方法計算された要約する今日は、Vue の計算プロパティについてお話ししましょう。計算プロパ...

JS での new の手書き実装

目次1 新しいオペレータの紹介2 新しいものは何をしましたか? 3 新しい演算子の実装をシミュレート...

Vue+Springbootでインターフェースシグネチャを実装するためのサンプルコード

1. 実装のアイデアインターフェース署名の目的は、リクエストパラメータが改ざんされていないか、リクエ...

Vue Routerはバックグラウンドデータに応じて異なるコンポーネントをロードします

目次実際のプロジェクトで遭遇する要件実装が間違っているところもある私は個人的に、実装するより良い方法...

CSS3を使用してボタンホバーフラッシュダイナミック特殊効果コードを実装する

CSS3 の列シリーズ属性を使用してウォーターフォールレイアウトを作成する方法を紹介しました。興味の...

一般的なテーブルコンポーネントの Vue カプセル化の完全な手順記録

目次序文テーブル コンポーネントをカプセル化する必要があるのはなぜですか?ステップ1: 共通コンポー...

Docker プライベートリポジトリの管理とローカルリポジトリ内のイメージの削除

1: Dockerプライベートウェアハウスのインストール1. イメージリポジトリからイメージをダウン...

nginx のロケーションと書き換えの使用法の詳細な説明

1. 位置情報の利用状況の概要ロケーションは、さまざまな処理方法に対してさまざまな種類のリクエストを...

Vue ElementUI フォームのフォーム検証

フォーム検証は、フロントエンド開発プロセスで最もよく使用される機能の 1 つです。私の個人的な仕事経...

Mac OS 10.11 での MySQL 5.7.12 のインストールと設定のチュートリアル

Mac OS 10.11 に MySQL をインストールして設定する方法を、主に写真を使って手順を簡...

フォーム内の無効なフォームフィールドの値を送信する方法 サンプルコード

フォーム内のフォーム フィールドが無効に設定されている場合、フォーム フィールドの値は送信されません...

nginx がどのようにして高いパフォーマンスとスケーラビリティを実現するのかを深く理解する

NGINX の全体的なアーキテクチャは、連携して動作する一連のプロセスによって特徴付けられます。メイ...

CSS 等高レイアウトの一般的な方法

等高レイアウト同じ親コンテナー内の同じ高さの子要素のレイアウトを指します。等高レイアウトの実装の観点...

ローカルでビルドした Docker イメージを Dockerhub に公開する方法

今日は、ローカルの Docker プロジェクト イメージを dockerhub に公開する方法を紹介...

Windows で nginx を素早くインストールし、自動的に起動するように設定する

目次1. Windows システムでの Nginx のインストールと起動プロセス: 2. 起動時にN...