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 高可用性デプロイメントの詳細な紹介

推薦する

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

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

ジョセフリング問題を解決する 3 つの JavaScript メソッド

目次概要問題の説明循環リンクリスト順序付き配列数学的再帰要約する概要ジョセフ・リング問題は、ジョセフ...

要素フォーム検証で検証プロンプトをクリアする方法

目次問題のシナリオ:解決: 1. フィールドを個別にチェックする2. フォームフィールドの下のフィー...

Docker がポート 2375 を公開し、サーバー攻撃を引き起こす問題と解決策

docker リモート API を学習した学生であれば、ポート 2375 についてよくご存知だと思い...

HTML のオートコンプリートを無効にして履歴を表示しないようにする

入力ボックスには、コンテンツを入力するときに常に入力履歴が表示されます。これを無効にする現在の方法は...

Vue2.x の応答性の簡単な説明と例

1. Vue レスポンシブの使用法を確認する​ Vue の応答性は、私たち全員がよく知っています。 ...

2級コンピュータ試験のMySQL知識ポイント mysql alterコマンド

テーブル構造を編集するための MySQL の alter コマンドの使用。具体的な内容は以下のとおり...

Nodejs 配列キューと forEach アプリケーションの詳細な説明

この記事では、Nodejs 開発プロセスで遭遇する配列の特性によって発生する問題と解決策、および配列...

リンクAの意味論、書き方、ベストプラクティス

リンク A のセマンティクス、ライティング スタイル、およびベスト プラクティス。私は JavaEy...

JavaScript ES6 モジュールの詳細な説明

目次0. モジュールとは何か1.モジュールの読み込み1.1 方法1 1.2 方法2 2. 輸出と輸入...

Centos7 esxi6.7 テンプレートの実際のアプリケーションの詳細な説明

1. Centos7.6システムを作成し、システムを最適化する1. NetworkManagerをオ...

MySQL データベースのバックアップをスケジュールするいくつかの方法 (包括的)

目次1. データをバックアップするためのmysqldumpコマンド2. 一般的なmysqldump操...

Linux システム構成 (サービス制御) の詳細な紹介

目次序文1. システムサービス制御1. システムctl 2. ターゲット3. 共通システムサービス4...

CSSアニメーションとSVGを組み合わせてエネルギーの流れの効果を作成する

最終的な効果は次のようになります。アニメーションは2つのステップに分かれていますランニング軌道を開発...

HTML いくつかの特別な分割線効果

1. 基本ライン 2. 特殊効果(効果は独立しておらず、互いに組み合わせることができます) 1. 両...