回答:
いいえ、ブロックしています。アルゴリズムの仕様をご覧ください。
ただし、MDNでは実装が理解しやすいかもしれません。
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisp, t[i], i, t);
}
};
}
要素ごとに多くのコードを実行する必要がある場合は、別のアプローチの使用を検討する必要があります。
function processArray(items, process) {
var todo = items.concat();
setTimeout(function() {
process(todo.shift());
if(todo.length > 0) {
setTimeout(arguments.callee, 25);
}
}, 25);
}
そしてそれを次のように呼び出します:
processArray([many many elements], function () {lots of work to do});
これは非ブロッキングになります。この例は、高性能JavaScriptから取られています。
別のオプションは、Webワーカーです。
forEach
せずawait
、for
ループを使用する必要があります。stackoverflow.com
await
内部async
関数のみを使用できます。しかしforEach
、非同期関数が何であるかはわかりません。非同期関数は単にpromiseを返す関数であることに注意してください。あなたは期待するforEach
コールバックから返された約束を処理するために?forEach
コールバックからの戻り値を完全に無視します。それ自体が非同期の場合のみ、非同期コールバックを処理できます。
の非同期対応バージョンなどが必要な場合Array.forEach
は、Node.jsの「非同期」モジュールで使用できます。http://github.com/caolan/async ...ボーナスとして、このモジュールはブラウザーでも機能します。
async.each(openFiles, saveFile, function(err){
// if any of the saves produced an error, err would equal that error
});
eachSeries
代わりにを使用する必要があります。
Nodeで非常に重い計算を行うための一般的なパターンがあり、それはあなたに適用できるかもしれません...
ノードはシングルスレッドです(設計上の意図的な選択として、Node.jsとはを参照してください)。つまり、単一のコアのみを利用できます。最近のボックスには8、16、またはそれ以上のコアがあるため、マシンの90%以上がアイドル状態になる可能性があります。RESTサービスの一般的なパターンは、コアごとに1つのノードプロセスを起動し、これらをhttp://nginx.org/のようなローカルロードバランサーの背後に配置することです。
子供をフォークする -あなたがやろうとしていることには、重いプロセスを行うために子プロセスをフォークする別の一般的なパターンがあります。利点は、親プロセスが他のイベントに応答している間に、子プロセスがバックグラウンドで重い計算を実行できることです。問題は、この子プロセスとメモリを共有できない、または共有してはならないことです(多くのゆがみといくつかのネイティブコードがないとできません)。メッセージを渡す必要があります。入力データと出力データのサイズが、実行する必要がある計算と比較して小さい場合、これは美しく機能します。子node.jsプロセスを起動して、以前使用していたのと同じコードを使用することもできます。
例えば:
var child_process = require( 'child_process'); function run_in_child(array、cb){ var process = child_process.exec( 'node libfn.js'、function(err、stdout、stderr){ var output = JSON.parse(stdout); cb(err、output); }); process.stdin.write(JSON.stringify(array)、 'utf8'); process.stdin.end(); }
2018-10-11を編集:以下で説明する標準が適用されない可能性が高いようです。パイプラインを代替として検討してください(まったく同じようには動作しませんが、メソッドは同様の方法で実装できます)。
これがまさに私がes7に興奮している理由です。将来、以下のコードのようなことができるようになります(一部の仕様は完全ではないので、注意して使用してください。これを最新に保つようにします)。ただし、基本的には、新しい::バインド演算子を使用すると、オブジェクトのプロトタイプにメソッドが含まれている場合と同じように、オブジェクトに対してメソッドを実行できます。例:[Object] :: [Method]通常は[Object]。[ObjectsMethod]を呼び出します
:今日(24 7月-16)この操作を行うと、それはあなたが次の機能のためにあなたのコードをtranspileする必要がありますすべてのブラウザで動作持っているノートのインポート/エクスポート、アロー機能、約束、非同期/待って、最も重要な機能のバインド。以下のコードは、必要に応じて関数バインドのみを使用するように変更することができます。この機能はすべて、babelを使用することにより、今日、きちんと利用できます。
YourCode.js( ' 行うべき多くの作業 'は、非同期の作業が行われたときにそれを解決するために、単にプロミスを返す必要があります。)
import { asyncForEach } from './ArrayExtensions.js';
await [many many elements]::asyncForEach(() => lots of work to do);
ArrayExtensions.js
export function asyncForEach(callback)
{
return Promise.resolve(this).then(async (ar) =>
{
for(let i=0;i<ar.length;i++)
{
await callback.call(ar, ar[i], i, ar);
}
});
};
export function asyncMap(callback)
{
return Promise.resolve(this).then(async (ar) =>
{
const out = [];
for(let i=0;i<ar.length;i++)
{
out[i] = await callback.call(ar, ar[i], i, ar);
}
return out;
});
};
これは、サードパーティのライブラリを必要とせずに使用する短い非同期関数です
Array.prototype.each = function (iterator, callback) {
var iterate = function () {
pointer++;
if (pointer >= this.length) {
callback();
return;
}
iterator.call(iterator, this[pointer], iterate, pointer);
}.bind(this),
pointer = -1;
iterate(this);
};
npmには、各ループの非同期を容易にするためのパッケージがあります。
var forEachAsync = require('futures').forEachAsync;
// waits for one request to finish before beginning the next
forEachAsync(['dogs', 'cats', 'octocats'], function (next, element, index, array) {
getPics(element, next);
// then after all of the elements have been handled
// the final callback fires to let you know it's all done
}).then(function () {
console.log('All requests have finished');
});
AllAsyncのもう 1つのバリエーション
たとえば、次のようなソリューションをコーディングすることもできます。
var loop = function(i, data, callback) {
if (i < data.length) {
//TODO("SELECT * FROM stackoverflowUsers;", function(res) {
//data[i].meta = res;
console.log(i, data[i].title);
return loop(i+1, data, errors, callback);
//});
} else {
return callback(data);
}
};
loop(0, [{"title": "hello"}, {"title": "world"}], function(data) {
console.log("DONE\n"+data);
});
一方、「for」よりもはるかに低速です。
それ以外の場合、優れたAsyncライブラリはこれを行うことができます:https : //caolan.github.io/async/docs.html#each
テストするために実行できる小さな例を次に示します。
[1,2,3,4,5,6,7,8,9].forEach(function(n){
var sum = 0;
console.log('Start for:' + n);
for (var i = 0; i < ( 10 - n) * 100000000; i++)
sum++;
console.log('Ended for:' + n, sum);
});
これは次のようなものを生成します(時間がかかりすぎる/時間がかかる場合は、反復回数を増やしたり減らしたりします)。
(index):48 Start for:1
(index):52 Ended for:1 900000000
(index):48 Start for:2
(index):52 Ended for:2 800000000
(index):48 Start for:3
(index):52 Ended for:3 700000000
(index):48 Start for:4
(index):52 Ended for:4 600000000
(index):48 Start for:5
(index):52 Ended for:5 500000000
(index):48 Start for:6
(index):52 Ended for:6 400000000
(index):48 Start for:7
(index):52 Ended for:7 300000000
(index):48 Start for:8
(index):52 Ended for:8 200000000
(index):48 Start for:9
(index):52 Ended for:9 100000000
(index):45 [Violation] 'load' handler took 7285ms
使用Promise.eachのブルーバードライブラリ。
Promise.each(
Iterable<any>|Promise<Iterable<any>> input,
function(any item, int index, int length) iterator
) -> Promise
このメソッドは、配列、または配列のpromiseを反復処理します。これには、値がaの解決された値であるシグネチャ(値、インデックス、長さ)を指定された反復関数を持つpromise(またはpromiseとvalueの混合)が含まれます入力配列のそれぞれの約束。反復は連続的に行われます。反復関数がpromiseまたはthenableを返す場合、次の反復を続行する前にpromiseの結果が待機されます。入力配列内のpromiseが拒否された場合、返されたpromiseも拒否されます。
すべての反復が正常に解決されると、Promise.each は変更されていない元の配列に解決されます。ただし、1つの反復で拒否またはエラーが発生した場合、Promise.eachはすぐに実行を中止し、それ以降の反復は処理しません。この場合、元の配列ではなく、エラーまたは拒否された値が返されます。
このメソッドは、副作用のために使用されることを意図しています。
var fileNames = ["1.txt", "2.txt", "3.txt"];
Promise.each(fileNames, function(fileName) {
return fs.readFileAsync(fileName).then(function(val){
// do stuff with 'val' here.
});
}).then(function() {
console.log("done");
});