【问题标题】:Node.js - Loop asyncNode.js - 循环异步
【发布时间】:2016-12-07 19:09:29
【问题描述】:

我是 nodejs 的新手,我试图在 for 循环中调用一个函数来打印一些东西。

var mysql = require("mysql"),
    async = require("async");

function test() {

    setTimeout(function () {
      console.log('boo');
    }, 100)
}

con.query('SELECT * FROM database', function(err, rows){
    if(err) throw err;

    for (var i = 0; i < rows.length; i++) {
        console.log('Processing ID: ' + rows[i].id);
        test();
    }

});

似乎循环并没有等待 boo 似乎继续遍历所有值。这是输出:

Processing ID: 1
Processing ID: 2
boo
boo

但我真正想要的是:

Processing ID: 1
boo
Processing ID: 2 
boo

我也尝试过像这样使用异步库:

async.each(rows, function(rows, callback) {         
    console.log('Processing ID: ' + rows.id);
    test();
    callback();

}, function(err) {
    if( err ) {
        console.log('A file failed to process');
    } else {
        console.log('All files have been processed successfully');
    }
});

【问题讨论】:

  • 使用setTimeout 呼叫打印到控制台会有 0.1 秒的延迟。但即使这样也不能解决问题。
  • 顺序对您的问题很重要吗?异步文档明确指出“注意,由于此函数将 iteratee 并行应用于每个项目,因此无法保证 iteratee 函数将按顺序完成。”
  • @aaaaaa 不是真的。但这是一个简单的例子,所以我可以理解这个过程。因为正在使用 webdriver 并且:“driver.wait(until.elementLocated...”。for 不会等待元素被定位并继续循环过程。
  • 试试 async.each(见我的回答)
  • 谁对所有答案投了反对票?我还在测试那些..

标签: javascript mysql node.js loops


【解决方案1】:

setTimeout 是异步的,不会阻塞其余代码。它基本上是在说“我将在 100 毫秒内调用console.log('boo'),同时继续执行其余代码”。 这与event loop 有关,这在talk 中有很好的解释。

使用异步库你可以使用eachSeries

async.eachSeries(
    rows,
    function(row, callback) {
      console.log('Processing ID: ' + row.id)
      setTimeout(function() { 
          console.log('boo')
          callback()
      }, 100)
    },
    function(){
        // is called when done
    }
)

eachSeries 将等待每次迭代,直到回调被调用。由于setTimeout 是异步的,您需要在那里调用回调。

工作 JSBin: https://jsbin.com/gequduhoma/1/edit?js,console

【讨论】:

  • 他没有问为什么输出会这样。
  • @Mahi 他做了:“但这是一个简单的例子,我可以理解这个过程。”
  • @ziad.ali 对不起,我错了,是eachSeries
  • @Moezalez 成功了!谢谢你。是否每个“回调();”意味着循环的下一次迭代?如果我想知道 for each 何时结束,我可以调用 'connection.end()' 我该怎么做?有这样的功能吗?
  • 是的,当回调被调用时,下一次迭代开始。完成后,将调用最后一个回调。见caolan.github.io/async/docs.html#eachSeries
【解决方案2】:

以下是您解决问题的方法

const async = require('async');
const processingIds = ['a1', 'b2', 'c3'];

function test(aProcessingId, done) {
  setTimeout(function () {
    console.log('Processing ID: ' + aProcessingId);
    console.log('boo');
    done();
  }, 100);
}

function iteratee(aProcessingId, done) {
  test(aProcessingId, done);
}

async.each(processingIds, iteratee);

打印出来的

Processing ID: a1
boo
Processing ID: b2
boo
Processing ID: c3
boo

你的代码有问题:

async.each(rows, function(rows, callback) {         
  console.log('Processing ID: ' + rows.id); // #1
  test(); // #2
  callback();

#1 - async.each 立即为您的所有行触发,这就是为什么 console.log 会立即为您的所有处理 ID 触发。

#2 - test() 启动一个新的异步函数,显示“在 0.1 秒内,键入“boo”,每个列表项执行一次。所以在打印所有进程 ID 0.1 秒后,boo 出现

【讨论】:

    猜你喜欢
    • 2015-04-11
    • 1970-01-01
    • 2015-02-27
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多