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

推薦する

Javascript Bootstrapのグリッドシステム、ナビゲーションバー、カルーセルの詳細な説明

目次ブートストラップと関連コンテンツの紹介グリッドシステムネストされた列列オフセット列の並べ替えナビ...

HTML 名 ID とクラスの違い_PowerNode Java アカデミー

名前タグの名前を指定します。形式 <input type="text" n...

MySQLトランザクションとMySQLログの詳細な説明

取引特性1. アトミック性: トランザクションの開始後、すべての操作が完了するか、まったく実行されな...

Reactベースのコンポーネントのカプセル化の実装手順

目次序文antd はどのようにしてコンポーネントをカプセル化するのでしょうか?ディバイダーコンポーネ...

組み込み Linux 開発環境で ping と nfs を構築するためのソリューション

1. 組み込みソフトウェアレベル 1) ブートローダ -> ブートローダ組み込みシステム全体の...

友達やグループを見つけるためのJavaScriptのLayim

現在、layuiの関係者はlayim友達検索ページの構造とスタイルを提供していません。私は個人的に非...

Hbase 入門

1. HBaseの概要1.1 HBaseとはHBase は、高い信頼性、高いパフォーマンス、列ストレ...

CentOS 7 で PHP 5.4 を 5.6 にアップグレードする方法の簡単な分析

1.ターミナルに入ったらPHPのバージョンを確認するphp -v出力は次のようになります。 PHP ...

ES6拡張演算子の理解と使用シナリオ

目次1. 適用メソッドを置き換え、関数を呼び出すときにパラメータを処理する2. 残りパラメータ(残り...

MySQL Community Server 5.6.39 のインストール方法

この記事では、MySQLのダウンロードとインストールの詳細なチュートリアルを記載しています。具体的な...

体験したい17 404ページ

404 を避けるべきだとどうして言えるのでしょうか? その理由は、ほとんどの 404 ページが粗雑す...

ウェブ開発者はIE7とIE8の共存を懸念している

今日、IE8 をインストールしました。ダウンロードするために Microsoft の Web サイト...

JavaScript の Set データ構造の詳細な説明

目次1. セットとは何か2. セットコンストラクタ2.1) 配列2.2) 文字列2.3) 議論2.4...

JSはclip-pathを使用して動的領域クリッピング機能を実装します

背景今日、CodePen を閲覧していたところ、非常に興味深い効果を見つけました。 CodePen ...

MySQL インデックスクエリ最適化スキルを習得するための記事

序文この記事では、DBA がいないチームが参考にできるように、MySQL の一般的な使用に関するヒン...