在JavaScript和Node.js中,Array.forEach是异步运行的吗?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (8)
  • 关注 (0)
  • 查看 (971)

在JavaScript中,Array.forEach是异步运行的吗?假设我调用以下代码:

[many many elements].forEach(function () {lots of work to do})

这会是非阻塞的吗?

提问于
用户回答回答于

算法规范

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});

High Performance JavaScript

另一个方法为 web workers

用户回答回答于

可以按照以下方式编写解决方案:

 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”慢得多。

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

用户回答回答于

以下为一个简短的异步函数,不需要第三方库。

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);
};
用户回答回答于

基本上使用new :: bind操作符,你将能够在对象上运行方法,类似对象的原型包含方法一样。 例如[Object] :: [Method],你可以调用[Object] .[ObjectsMethod]

要做到所有的浏览器中都能运行,你需要为你的代码编译以下功能:导入/导出,Arrow functions,Promises,异步/等待和最重要的函数绑定。 以下代码可以被修改为只使用函数绑定,如果有必要的话,所有这些功能都可以通过使用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.forEach用于计算不等待的东西,并且在事件循环中进行异步计算(如果需要多核计算的话,WebWork会添加多处理)。如果要等待多个任务结束,可以使用计数器,并计数器包装在信号量类中。

用户回答回答于

有一种常见的模式,用于在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,可以在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
});

扫码关注云+社区

领取腾讯云代金券