JavaScript/TypeScript で同時リクエスト制御を実装するためのサンプルコード

JavaScript/TypeScript で同時リクエスト制御を実装するためのサンプルコード

シナリオ

リクエストが 10 件あるが、同時リクエストの最大数は 5 件で、リクエスト結果が必要であるとします。これは、単純な同時リクエスト制御です。

シミュレーション

setTimeoutを使用してリクエストの簡単なシミュレーションを実行します

startTime を Date.now() とします。
const タイムアウト = (タイムアウト: 数値, ret: 数値) => {
 戻り値 (idx?: 任意) =>
 新しいPromise((resolve) => {
  タイムアウトを設定する(() => {
  const compare = Date.now() - startTime;
  console.log(`${Math.floor(compare / 100)}00 で return`, ret);
  解決(idx);
  }、 タイムアウト);
 });
};

定数timeout1 = timeout(1000, 1);
定数timeout2 = timeout(300, 2);
定数timeout3 = タイムアウト(400, 3);
定数timeout4 = タイムアウト(500, 4);
定数timeout5 = タイムアウト(200, 5);

このようにリクエストをシミュレートすることで、本質はPromiseになります

同時実行制御がない場合

定数実行 = 非同期() => {
 開始時刻 = Date.now();
 Promise.all([ を待つ
 タイムアウト1()、
 タイムアウト2()、
 タイムアウト3()、
 タイムアウト4()、
 タイムアウト5()、
 ]);
};

走る();

200で5を返す
300で2を返す
400で3を返す
500で4を返す
1000で1を返す

出力は 5 2 3 4 1 となっており、タイムアウト時間に応じて出力されていることがわかります。

同時実行条件

同時接続の最大数が2であると仮定して、クラスを作成します

クラスConcurrent {
 プライベートmaxConcurrent: 数値 = 2;

 コンストラクター(count: number = 2) {
 this.maxConcurrent = カウント;
 }
}

最初の同時実行制御

考えてみてください。同時実行の最大数に応じて Promise 配列を分割します。Promise が満たされた場合はそれを削除し、保留中の Promise を追加します。 Promise.raceはこの要件を満たすのに役立ちます

クラスConcurrent {
 プライベートmaxConcurrent: 数値 = 2;

 コンストラクタ(count: number = 2) {
 this.maxConcurrent = カウント;
 }
 パブリック非同期useRace(fns: Function[]) {
 const 実行中: any[] = [];
 // 同時実行数に応じて Promise を追加します // Promise はインデックスをコールバックするので、どの Promise が解決されたかを知ることができます (let i = 0; i < this.maxConcurrent; i++) {
  (fns.長さ)の場合{
  const fn = fns.shift()!;
  実行中.push(fn(i));
  }
 }
 定数ハンドル = 非同期() => {
  if (fns.length) {
  const idx = await Promise.race<number>(running);
  const nextFn = fns.shift()!;
  // 完了した Promise を削除し、新しいものを runing.splice(idx, 1, nextFn(idx)); に配置します。
  ハンドル();
  } それ以外 {
  // 配列がクリアされている場合は、実行される Promise がないことを意味します。これを Promise.all に変更できます。
  Promise.all(実行中) を待機します。
  }
 };
 ハンドル();
 }
}

定数実行 = 非同期() => {
 const コンカレント = 新しい Concurrent();
 開始時刻 = Date.now();
 同時実行のuseRace([タイムアウト1、タイムアウト2、タイムアウト3、タイムアウト4、タイムアウト5])を待機します。
};

300で2を返す
700で3を返す
1000で1を返す
1200に5を返す
1200に4に戻る

出力が変化したことがわかります。なぜこのようなことが起こるのでしょうか? 分析してみましょう。同時接続の最大数は 2 です。

// 最初に実行するのは 1 2
1 完了するには1000MSかかります
2 300 MS必要

2 が実行されると、タイムラインは 300 になります。2 を削除します。3 を追加します。3 の実行を開始します。
3 は 400 ミリ秒かかります。実行時間は 700 ミリ秒になります。3 を削除します。4 を追加します。4 の実行を開始します。
4 500MSが必要
タイムラインが1000MSに達すると、1つが実行されて削除され、5つが追加され、5つが開始されます。
タイムラインが1200MSに到達し、ステップ4と5が同時に実行されます。

2番目のオプション

awaitメカニズムを使うことができます。これは実際にはちょっとしたトリックです

await 式は、現在の async 関数の実行を一時停止し、Promise が完了するまで待機します。 Promise が満たされると、コールバックの解決関数パラメータが await 式の値として使用され、非同期関数の実行が続行されます。

現在の同時リクエスト数が最大同時リクエスト数を超える場合は、新しい Promise を設定して待機できます。他のリクエストが完了するのを待機している場合は、解決して待機を削除します。そのため、現在の同時リクエスト数と、解決コールバック関数を格納する配列という 2 つの新しい状態を追加する必要があります。

クラスConcurrent {
 プライベートmaxConcurrent: 数値 = 2;
 プライベートリスト: Function[] = [];
 プライベートcurrentCount: 数値 = 0;

 コンストラクタ(count: number = 2) {
 this.maxConcurrent = カウント;
 }
 パブリック非同期追加(fn:関数) {
 this.currentCount += 1;
 // 同時接続の最大数が最大値を超えた場合 if (this.currentCount > this.maxConcurrent) {
  // wait は Promise であり、resolve が呼び出される限り満たされます。const wait = new Promise((resolve) => {
  this.list.push(解決) を実行します。
  });
  //resolve が呼び出されない場合、ここで await wait がブロックされます。
 }
 //関数を実行する await fn();
 this.currentCount -= 1;
 if (this.list.length) {
  // 解決を取り出して呼び出すと、待機が完了し、以下を実行できるようになります。const resolveHandler = this.list.shift()!;
  ハンドラを解決します。
 }
 }
}

定数実行 = 非同期() => {
 const コンカレント = 新しい Concurrent();
 開始時刻 = Date.now();
 同時実行を追加します(タイムアウト1);
 同時実行を追加します(タイムアウト2)。
 同時実行を追加します(timeout3);
 同時実行を追加します(タイムアウト4)。
 同時実行を追加します(timeout5);
};

走る();

300で2を返す
700で3を返す
1000で1を返す
1200に5を返す
1200に4に戻る

要約する

どちらの方法でも並行制御を実現できますが、実装方法が異なります。主に Promise によって実装されます。また、実装方法は異常事態を考慮しておらず、自分で追加できる可能性があります。

これで、JavaScript/TypeScript で同時リクエスト制御を実装するサンプルコードに関する記事は終了です。JavaScript の同時リクエスト制御に関する詳細については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript のプライベート クラス フィールドと TypeScript のプライベート修飾子の詳細な説明
  • JS デコレータ パターンと TypeScript デコレータ
  • TypeScriptでのRxJSの簡単な使い方の詳しい説明
  • Vue.js で TypeScript を使用する方法
  • JavaScript と TypeScript における void の具体的な使用法
  • Typescript nodejs 依存性注入実装コードの詳細な説明
  • vue + typescript + video.js でストリーミングビデオ監視機能を実現
  • TypeScriptを使用してNode.jsアプリケーションを開発する方法を教えます
  • JavaScriptとTypeScriptの関係

<<:  js 加算、減算、乗算、除算の正確な計算方法のサンプルコード

>>:  MySQL 5.7.17 winx64 のインストールと設定方法のグラフィックチュートリアル

推薦する

CentOS7.x のアンインストールとインストール MySQL5.7 の操作手順とエンコード形式の変更方法

1. MySQL 5.7 のアンインストール1.1查看yum是否安裝過mysql CD yum li...

ウェブページの画像の回転を実現するjs

この記事では、Webページの画像の回転を実現するためのjsの具体的なコードを参考までに共有します。具...

MySQL レプリケーション テーブルの詳細とサンプル コード

MySQL レプリケーション テーブルの詳細な説明テーブル構造、インデックス、デフォルト値などを含む...

デプロイから基本操作までDocker Swarm

Docker SwarmについてDocker Swarm は次の 2 つの部分で構成されます。 D...

jQueryブリージングカルーセルの制作原理を詳しく解説

この記事では、jQueryブリージングカルーセル制作原理の具体的なプロセスを参考までに紹介します。具...

JavaScript オブジェクト指向クラス継承ケースの説明

1. オブジェクト指向のクラス継承これまでの章では、JavaScript のオブジェクト モデルがプ...

CSSは親要素の下の最初の子要素を選択します(:first-child)

序文最近、プロジェクトで :first-child を使用したのですが、すぐに思いつきました。これは...

Linux での VMWare15.5 のインストールに関するチュートリアル

Linux に VMWare をインストールするには、公式 Web サイト https://www....

子要素の margin-top によって親要素が移動する問題の解決方法

問題の説明今日、ページ スタイルを変更していたときに、子要素にmargin-top設定したのに、子要...

曇り空のアイコン効果を実現する純粋な CSS

効果効果は以下のとおりです​実装のアイデアbox-shadow プロパティを使用して、複数の灰色の円...

MySQL 8.0.17 解凍版のインストールと設定方法のグラフィックチュートリアル

インストール中に遭遇した問題を記録しておきますので、皆様のお役に立てれば幸いです。 1. ダウンロー...

docker compose の記述ルールについての簡単な説明

この記事ではクラスタの展開に関連する内容は紹介しませんバージョン制約Docker エンジン >...

すべてのブラウザとの完全な互換性を実現するために最適なプリセットを選択してください

各ブラウザの select タグのプロパティと各ブラウザのサポートが多少異なるため、各ブラウザでの選...

Linuxサービスの監視と運用および保守

目次1. psutilパッケージをインストールする次に、オペレーティングシステム内のすべてのサービス...

MySQL 文字列分割操作 (区切り文字を含む文字列のインターセプション)

区切り文字なしの文字列抽出質問の要件データベース内のフィールド値:実装効果: 1行のデータを複数行に...