首页 > 解决方案 > Node.js 事件循环忽略读取流数据事件中的 setTimeout?

问题描述

我正在澄清我对 Node.js 如何执行计时器的疑问。通常,当您的节点脚本中有一个 setTimeout 块时,事件循环,即使没有其他任何内容,也会在 setTimeout 中等待指定的毫秒数,并在运行回调后退出。

但考虑下面的代码

const fs = require('fs');

let readable = fs.createReadStream('large.csv');
readable.on('data', async chunk => {
    let rows = parseCsvRow(chunk);  
    try {
        for (let i = 0; i < rows.length; i++) {
            console.log(i);
            await someAsyncOperation(rows[i]);
        }
    } catch (error) {
        //something went wrong
    }
});

readable.on('end', chunk => {
    console.log('csv file processed successfully');
});

function someAsyncOperation(){
    return new Promise((resolve, reject) => {
        setTimeout(resolve, 2000);
    });
}

我正在阅读的 csv 文件有大约 300 行,我正在为每个(为简单起见隐藏代码)触发一个 ajax 请求,运行大约需要 100 毫秒,我在这里使用 setTimeout 对其进行了模拟。

当我运行上面的程序时,它几乎立即退出,而无需等待所有挂起的 setTimeout 计时器成功运行。仅仅因为从data读取流上的事件内部安排的计时器会忽略它吗?它不应该等待所有计时器执行吗?

注意 - 我知道上面的代码不是做我正在做的事情的正确方法,但这只是一个示例,用于展示我很难理解的概念。

标签: javascriptnode.jsevent-loop

解决方案


这与 Node.js 或事件循环无关。

问题是你将一个async函数传递给一个不会对它返回的承诺做任何事情的东西。这是承诺的反模式之一。仅async当以下之一为真时,才将函数用作回调:

  • 执行回调的事物将使用或返回承诺(例如,Promise.all因为它使用它们,或者map在数组上因为它返回它们)
  • 您不在乎调用您的async函数的东西是否继续工作,而您的async函数可能会暂停在 上await并且async您将函数中的所有内容包装在处理拒绝的try/中。catch

Node.js 的特定部分是:如果您想阻止对data处理程序的进一步调用,直到您完成某些操作,您需要先调用pause流,然后再调用resume它。


推荐阅读