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

推薦する

円形/扇形メニューを2分で実装する方法を教えます(基本バージョン)

序文このプロジェクトでは円形のメニューが必要です。オンラインで検索しましたが、適切なものが見つからな...

ubuntu20.04 LTS システムのデフォルト ソース ソース リスト ファイルの変更

誤って source.list の内容を変更し、一連のエラーが発生した場合は、デフォルトのソース フ...

Unicode 署名 BOM の詳細な説明

Unicode 署名 BOM - BOM とは何ですか? BOM は Byte Order Mark...

iframe を更新する 3 つの方法

コードをコピーコードは次のとおりです。 <iframe src="1.htm&quo...

mysql5.7.24 バージョンのインストール手順と解凍時に発生した問題の概要

1. ダウンロード参考: 2. D:\MySQL\mysql-5.7.24 などの固定の場所に解凍し...

Vue3における非親子コンポーネント通信の詳細な説明

目次最初の方法アプリ.vueホーム.vueホームコンテンツ.vueデータの応答性レスポンシブプロパテ...

DELL R730 サーバーの構成 RAID とインストール サーバー システムとドメイン制御の詳細なグラフィック チュートリアル

最近、会社で DELL R730 サーバーを購入したのですが、偶然次のチュートリアルを見つけたので、...

crontab の実行結果を電子メールでユーザーに通知する方法

症状Centos7 ホストに crontab タスクを設定しましたが、時間が来るとメールを実行して「...

resizeを使用して画像切り替えプレビュー機能を実装する方法

要点CSS resize プロパティを使用すると、要素のサイズ変更可能性を制御できます。サイズ変更を...

シンプルな計算機を実装するためのネイティブ js

この記事の例では、参考までに簡単な計算機を実装するためのjsの具体的なコードを共有しています。具体的...

MySQL ストレステストツール Mysqlslap の使用

1. MySQL独自のストレステストツールMysqlslap mysqlslap は、mysql に...

トップナビゲーションバー機能を実現するCSS+HTML

ナビゲーション バー、固定トップ ナビゲーション バー、およびセカンダリ メニューの実装効果図の実装...

IE ラベル LI テキスト折り返し問題について

私は長い間この問題に悩まされていましたが、検索してみたところ、実際にこの問題を解決した人がいることが...

Vueは、サイドナビゲーションバーをタブページに関連付けるサンプルコードを実装します。

目次テクノロジースタック効果分析するテクノロジースタックサイドバー用Antdtabは要素を使用します...

HTMLの行間設定方法と問題点

<p></p> の行間隔を設定するには、style="line-h...