JavaScript におけるシリアル操作と並列操作

JavaScript におけるシリアル操作と並列操作

1. はじめに

この記事では、 jses5およびes6における非同期関数、シリアル実行、並列実行のソリューションについて説明します。例はシリアルとパラレルの組み合わせで使用されています。

2. es5メソッド

es6 が登場する前から、 nodejsコミュニティにはコールバック地獄に対処するためのpromiseソリューションがすでに存在していました。非同期関数が複数ある場合、実行シーケンスをどのように配置すればよいでしょうか? すべての非同期関数をより速く実行し、次のステップに進むにはどうすればよいでしょうか?ここで、js のシリアル実行と並列実行の問題が発生します。

3. 非同期関数のシリアル実行

var アイテム = [ 1, 2, 3, 4, 5, 6 ];
var 結果 = [];

関数 async(arg, コールバック) {
  console.log('パラメータは ' + arg +' です。1 秒後に結果を返します');
  setTimeout(function() { callback(arg * 2); }, 1000);
}

関数final(値) {
  console.log('完了しました: ', 値);
}

関数シリーズ(アイテム) {
  if(アイテム) {
    非同期(項目、関数(結果) {
      結果をプッシュします。
      return series(items.shift()); // すべてのデータを再帰的に実行します });
  } それ以外 {
    final(results[results.length - 1]) を返します。
  }
}

シリーズ(items.shift());

4. 非同期関数の並列実行

上記の関数は一つずつ実行され、前の関数が終了してから次の関数が実行されますが、これはes6の async と await (es5 以降は総称して es6 と呼びます) に似ていpromise.all 。promise.all のようにすべてを並列実行できるものはありますか?

次のように書くことができます。

var アイテム = [ 1, 2, 3, 4, 5, 6 ];
var 結果 = [];

関数 async(arg, コールバック) {
  console.log('パラメータは ' + arg +' です。1 秒後に結果を返します');
  setTimeout(function() { callback(arg * 2); }, 1000);
}

関数final(値) {
  console.log('完了しました: ', 値);
}

items.forEach(function(item){// ループ完了 async(item, function(result){
    結果をプッシュします。
    if(results.length === items.length){// 完了した関数の数が実行される関数の数と等しいかどうかを判断します final(results[results.length - 1]);
    }
  })
});

5. 非同期関数のシリアル実行と並列実行の組み合わせ

多数の非同期データ(数百個)が並列に実行され、各非同期データに大量の(https)リクエストデータが含まれている場合、TCP 接続が不足したり、無数のコールスタックが蓄積されてメモリオーバーフローが発生する可能性があります。そのため、大量のデータを並列に実行するのは容易ではなく、並列方式と直列方式を組み合わせた方法が登場しました。

コードは次のように記述できます。

var アイテム = [ 1, 2, 3, 4, 5, 6 ];
var 結果 = [];
var 実行中 = 0;
var 制限 = 2;

関数 async(arg, コールバック) {
  console.log('パラメータは ' + arg +' です。1 秒後に結果を返します');
  setTimeout(function() { callback(arg * 2); }, 1000);
}

関数final(値) {
  console.log('完了しました: ', 値);
}

関数ランチャー() {
  while(実行中 < limit && items.length > 0) {
    var item = items.shift();
    非同期(項目、関数(結果) {
      結果をプッシュします。
      実行中--;
      (アイテムの長さ>0)の場合{
        ランチャー();
      } そうでない場合(実行中 == 0) {
        最終(結果);
      }
    });
    実行中++;
  }
}

ランチャー();

6. es6メソッド

es6は当然、シリアル実行方式と並列実行方式が付属しています。たとえば、シリアルではasyncawait (前の記事で説明) を使用でき、並列では promise.all などを使用できます。次に、シリアル操作と並列操作を組み合わせて同時実行のpromise all呼び出しの数を制限するために、コミュニティには次のような解決策もあります。

tiny-async-pool、es6-promise-pool、p-limit


promise all同時実行数制限ソリューション関数の単純なカプセル化

function PromiseLimit(funcArray, limit = 5) { // 5つのデータを同時に実行 let i = 0;
  定数結果 = [];
  const 実行 = [];
  定数キュー = 関数() {
    if (i === funcArray.length) の場合、Promise.all(executing) を返します。
    const p = funcArray[i++]();
    結果をpushします。
    const e = p.then(() => execute.splice(executing.indexOf(e), 1));
    実行中.push(e);
    if (実行中の長さ >= 制限) {
      Promise.race(実行中).then( を返す
        () => キュー()、
        e => Promise.reject(e)
      );
    }
    Promise.resolve() を返します。その後 (() => queue());
  };
  キュー()を返します。その後()=> Promise.all(結果));
}

使用:

// テストコード const result = [];
(インデックス = 0、インデックス < 10、インデックス++) {
  結果.push(関数() {
    新しい Promise を返します ((resolve, reject) => {
      console.log("start" + インデックス、新しい Date().toLocaleString());
      タイムアウトを設定する(() => {
        解決(インデックス);
        console.log("End" + インデックス、新しいDate().toLocaleString());
      }, parseInt(Math.random() * 10000));
    });
  });
}

PromiseLimit(結果).then(データ => {
  コンソールにログ出力します。
});

テストコードを修正し、ランダムな失敗ロジックを追加する

// テストコードを変更して、ランダムに失敗または成功するようにします。const result = [];
(インデックス = 0、インデックス < 10、インデックス++) {
  結果.push(関数() {
    新しい Promise を返します ((resolve, reject) => {
      console.log("start" + インデックス、新しい Date().toLocaleString());
      タイムアウトを設定する(() => {
        もし(Math.random() > 0.5){
          解決(インデックス);
        } それ以外 {
          拒否(インデックス);
        }
        console.log("End" + インデックス、新しいDate().toLocaleString());
      }, parseInt(Math.random() * 1000));
    });
  });
}
PromiseLimit(結果).then(
  データ => {
    console.log("成功", データ);
  },
  データ => {
    console.log("失敗", データ);
  }
);

7. asyncとawaitをpromiseと組み合わせる

非同期関数 PromiseAll(promises,batchSize=10) {
 定数結果 = [];
 while(promises.length > 0) {
   const データ = Promise.all(promises.splice(0,batchSize)) を待機します。
   結果.push(...データ);
 }
結果を返します。
}

この文章には 2 つの問題があります。

  • 1. promisesPromise.allを呼び出す前に作成されるpromise 、実際に実行される
  • 2. 実装では、次のbatchSizeを実行する前に、前のbatchSize個promise resolve待つ必要があります。つまり、 promise all成功する必要があります。

改善点は次のとおりです。

非同期関数 asyncPool(配列、poolLimit、iteratorFn) {
  定数ret = [];
  const 実行 = [];
  for (配列のconst項目) {
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p);

    プール制限 <= 配列の長さの場合 {
      const e = p.then(() => execute.splice(executing.indexOf(e), 1));
      実行中.push(e);
      実行中の長さ >= poolLimit の場合 {
        Promise.race(実行中) を待機します。
      }
    }
  }
  Promise.all(ret) を返します。
}

使用:

const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
asyncPool( [1000, 5000, 3000, 2000], 2,timeout)を返します。その後(結果 => {
    ...
});

JavaScript の非同期操作におけるシリアル操作と並列操作に関するこの記事はこれで終わりです。JavaScript の非同期操作におけるシリアル操作と並列操作に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript 非同期操作の一般的な処理方法の概要
  • $q.all を使用して Angularjs 非同期操作バックグラウンド リクエストの順序を並べ替える問題を解決する
  • ES6 JavaScriptの非同期操作例の詳しい説明
  • async/await と promise (Node.js における非同期操作の問題)
  • Thinkjs ページジャンプの同期および非同期操作
  • JavaScript-Mongooseデータクエリの非同期操作を解決する
  • シンプルなNode.js非同期操作マネージャの共有

<<:  MySQLユーザー権限テーブルについての簡単な説明

>>:  seata docker 高可用性デプロイメントの詳細な紹介

推薦する

CentOS7 ファイアウォールとオープンポートの簡単な使い方の簡単な紹介

概要(公式にはより詳しい説明があります) Firewalld は、ネットワーク接続またはインターフェ...

JavaScript の基礎におけるデータ型の詳細な説明

目次1. データ型1.1 なぜデータ型が必要なのか? 1.2 変数のデータ型1.3 データ型の分類2...

MySql テーブル、データベース、シャーディング、パーティショニングの知識の詳細な説明

1. はじめにデータベース内のデータ量が一定レベルに達すると、システムパフォーマンスのボトルネックを...

js シンプルで粗雑なパブリッシュとサブスクライブのサンプルコード

パブリッシュ/サブスクライブとは何ですか?例を挙げてみましょう。あなたは服を買うために店に行きます。...

Vue で rem 適応を使用する方法

1. 開発環境vue 2. コンピュータシステム Windows 10 Professional E...

JavaScriptはボタンをクリックして4桁のランダムな検証コードを生成します

この記事の例では、ボタンをクリックすることで4桁のランダムな検証コードを生成するjsの具体的なコード...

CSSの一般的なプロパティ

CSS の背景: background:#00ffee; //背景色を設定するbackground-...

React の調整アルゴリズム Diffing アルゴリズム戦略の詳細な説明

目次アルゴリズム戦略単一ノードの差分配列ノードの差分キー値の使用要件アルゴリズム戦略React の調...

JavaScript 初心者のための二分探索木アルゴリズムのチュートリアル

目次バイナリ検索木 (BST) とは何ですか?バイナリツリーの基本的な走査(インオーダー、ポストオー...

MySQLカスタム関数の簡単な使用例

この記事では、例を使用して MySQL カスタム関数の使用方法を説明します。ご参考までに、詳細は以下...

MySQLトリガーの例の詳細な説明

目次トリガーとは何かトリガーを作成する複数の実行ステートメントを持つトリガーの作成制限と考慮事項要約...

WeChatアプレットがジグソーパズルゲームを実装

この記事では、WeChatアプレットでジグソーパズルゲームを実装するための具体的なコードを参考までに...

CentOS 8.1 で LEMP (Linux+Nginx+MySQL+PHP) 環境を構築する (チュートリアルの詳細)

目次ステップ1: CentOS 8でパッケージを更新するステップ2: CentOS 8にNginx ...

MySQLクエリ最適化: 100万件のデータに対するテーブル最適化ソリューション

1. 2つのクエリエンジン(myIsamエンジン)のクエリ速度InnoDB はテーブル内の特定の行数...

MySQL DATE_FORMAT関数の使用

タオバオが、ダブル11に最も多くの注文をした2人のユーザー、ユーザー1:「ショッピングの皇帝、陳哈哈...