Array.forEach
实现的问题:它是否表现为异步的?
例如,如果我调用:[many many elements].forEach(function () {lots of work to do})
这会是非阻塞的吗?
Array.forEach
实现的问题:它是否表现为异步的?
例如,如果我调用:[many many elements].forEach(function () {lots of work to do})
这会是非阻塞的吗?
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 Workers。
async
(https://www.npmjs.org/package/async)可能是更合适的解决方案(事实上我刚看到有人把它作为答案发布了!)。 - JamesforEach
时不会阻塞 await
语句,你应该使用 for
循环代替:http://stackoverflow.com/questions/37962880/why-does-await-not-wait-and-why-does-sequelize-neither-respond-nor-error?noredirect=1#comment63373960_37962880 - Richardawait
。但是forEach
不知道什么是异步函数。请记住,异步函数只是返回Promise的函数。你是否期望forEach
处理从回调函数返回的Promise?forEach
完全忽略回调的返回值。如果回调本身不是异步的,它只能处理非异步回调。 - Felix Kling如果你需要一个异步友好的Array.forEach
等函数,它们可以在Node.js的'async'模块中找到: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
。 - matpop有一种在Node中进行重型计算的常见模式,可能适用于您...
Node是单线程的(作为一个故意设计的选择,请参见什么是Node.js?);这意味着它只能利用一个核心。现代盒子有8、16甚至更多的内核,因此这可能会使机器的90%以上处于空闲状态。 REST服务的常见模式是为每个核心启动一个节点进程,并将它们放在本地负载均衡器后面,例如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(); }
Array.forEach
的作用是计算,而不是等待,如果在事件循环中将计算变成异步的话,并没有什么好处(如果需要多核计算,则可以使用WebWorkers来添加多进程)。如果你想要等待多个任务结束,请使用一个计数器,你可以将其包装在一个信号量类中。
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;
});
};
/* eslint-disable no-console */
async function forEachTest() {
console.log('########### Testing forEach ################ ')
console.log('start of forEachTest func')
let a = [1, 2, 3]
await a.forEach(async (v) => {
console.log('start of forEach: ', v)
await new Promise(resolve => setTimeout(resolve, v * 1000))
console.log('end of forEach: ', v)
})
console.log('end of forEachTest func')
}
forEachTest()
async function forOfTest() {
await new Promise(resolve => setTimeout(resolve, 10000)) //just see console in proper way
console.log('\n\n########### Testing forOf ################ ')
console.log('start of forOfTest func')
let a = [1, 2, 3]
for (const v of a) {
console.log('start of forOf: ', v)
await new Promise(resolve => setTimeout(resolve, v * 1000))
console.log('end of forOf: ', v)
}
console.log('end of forOfTest func')
}
forOfTest()
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);
};
就算是像这样的解决方案,也可以进行编码:
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
在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');
});
还有另一种变体 forAllAsync
这里有一个小例子,你可以运行来测试它:
[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