【问题标题】:Node.js / Is for loop is Async?Node.js / 是 for 循环是异步的吗?
【发布时间】:2015-02-24 20:25:04
【问题描述】:

我有以下代码:

for (var i = 0; i < files.length; i++) {
    var data = fs.readFileSync(files[i]);
    fs.appendFileSync("file_part", data);
}

假设我有 1000 个文件。它是for循环异步吗?或者我的应用程序将等到它完成该过程?

如果它同步,我如何使它异步?所以每次迭代都是异步的?

编辑

此代码是服务器代码的一部分,使用 express。我们收到很多 https 请求,并为客户服务。其中一项操作是将 1MB 的文件附加到一个大文件中。如果操作成功,服务器应该返回 200,否则返回 500。

问题是如果上面的代码(for循环)被执行,express模块​​停止服务其他客户端,并且它“忙于”这个请求。我尝试使用async.eachSeries(因为文件的顺序有含义,所以我必须使用Series方法),但它仍然卡在服务器上。

【问题讨论】:

  • 它是同步的,因为您使用的是同步方法。如果要使其异步,请阅读documentation 并改用异步方法。
  • 如果要让它异步,你真的要并行打开1000个文件吗?还是您希望它们按顺序执行?如果是这样,您已有的解决方案有什么问题?
  • 你那里似乎有一个流浪者)。这段代码还能运行吗?
  • @Bergi:我编辑问题并解释我的解决方案有什么问题。

标签: javascript node.js asynchronous


【解决方案1】:

JS中的所有控制结构都是同步执行的。由于您在循环体中没有使用异步函数(而是显式同步的对应函数),因此它将等待它们完成任务。


要使 sn-p 非阻塞,您需要使用常规的异步 fs 方法,并将它们适当地链接起来。我会推荐 Promise,但如果你已经在使用 ,那么它应该是这样的:

async.eachSeries(files, function(file, cb) {
    fs.readFile(file, function(err, data) {
        if (err) return cb(err);
        fs.appendFile("file_part", data, cb);
    });
}, function(err) {
    // call back to express here with 500 if err and 200 otherwise
});

【讨论】:

  • 我的问题是我需要将 1000 个 1 MB 的文件附加到一个 1 GB 的文件中。我的问题中的代码“卡住”了我的服务器,直到所有附加过程完成。所以我的问题是我需要读取文件同步性(因为字节的顺序很重要,但我不想阻止它)。我尝试使用 async.eachSeries,但它也卡住了我的服务器。
  • @MiddleWare:你用过async.eachSeries的同步函数吗?
【解决方案2】:

如果您只想将文件列表异步连接在一起,您可以在对fs.readFile 的回调中执行此操作:

function concatFiles (source_array, destination) {
    var source = source_array.shift();

    fs.readFile(source,function(err,data){
        fs.appendFile(destination,data,function(err){
            if (source_array.length) {
                concatFiles(source_array, destination);
            }
        });
    });
}

// Usage:
concatFiles(files,"file_part");

请注意,为了清楚起见,我没有处理上面代码中的错误。在生产代码中,您应该检查错误并适当地处理它们。

发生了什么很明显。弹出源列表中的第一个文件。然后异步读取该文件。然后,完成后异步写入目标文件。重复直到源列表为空。

【讨论】:

    【解决方案3】:

    这个问题和你想要做的事情都有几个问题。您可能想澄清问题或澄清您真正想做的事情。

    对您的问题的简短回答:不。for 循环本身并不是异步的。

    稍微长一点的答案:不清楚您是否需要循环本身是异步的,但您可能只希望内容是异步的。因此,您可能不想使用readFileSync,而是使用带有回调的readFile。在此回调中,您可以附加到文件。这将“触发” 1000 个读取文件,准备就绪时将调用它们的回调。

    但还是有问题。如果你异步读取这1000个文件,并在读取时将它们保存到同一个文件中,你将无法按任何顺序获取文件内容,并且甚至可能有文件内容交错。我无法想象你为什么要这么做。

    更新:您更新的问题仍然有点模糊 - 如果您需要等到一切都完成发送代码 200 回复...那么您将不得不等到所有文件被附加。确实没有其他解决方案。

    但是,如果您可以立即返回代码 200 以指示您正在处理文件追加,然后在后台执行追加,则可以将循环作为异步任务的一部分执行。您可以在 process.nextTick() 调用中或在 Promise 中或以任何其他对您的流程有意义的方式执行此操作。

    【讨论】:

    • 我的问题是我需要将 1000 个 1 MB 的文件附加到一个大小为 1GB 的文件中。我的问题中的代码“卡住”了我的服务器,直到所有附加过程完成。所以我的问题是我需要读取文件同步性(因为字节的顺序很重要,但我不想阻止它)。我尝试使用 async.eachSeries,但它也卡住了我的服务器。
    • 您能否澄清一下,可能在原始问题中,是否需要将此文件作为流程的一部分返回,以及为什么让服务器暂停以执行此工作是不合理的?
    • 更新了答案,以反映您在回复用户时需要考虑的事项。
    猜你喜欢
    • 2015-04-11
    • 2014-02-06
    • 2021-10-18
    • 1970-01-01
    • 2015-02-11
    • 2011-11-08
    • 2012-09-27
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多