node.js是否保留异步执行顺序?

时间:2012-06-28 03:55:20

标签: node.js asynchronous

我想知道node.js是否对订单异步调用启动/完成提供任何保证。

我认为不行,但我已经在互联网上阅读了一些我认为会有错误的代码示例,因为异步调用可能无法按预期顺序完成,但这些示例通常在如何说明伟大的节点是因为它的单线程异步模型。但是我找不到这个一般性问题的直接答案。

不同的节点模块是否有不同的保证?例如,在https://stackoverflow.com/a/8018371/1072626,答案清楚地表明涉及Redis的异步调用保留了顺序。

这个问题的症结可归结为以下执行(或类似)在节点中是否严格安全?

var fs = require("fs");
fs.unlink("/tmp/test.png");
fs.rename("/tmp/image1.png", "/tmp/test.png");

根据作者的说法,需要调用unlink,因为如果存在预先存在的文件,则重命名将在Windows上失败。但是,这两个调用都是异步的,所以我最初的想法是对rename的调用应该在unlink的回调中,以确保在异步rename操作开始之前异步I / O完成否则rename可能会先执行,导致错误。

2 个答案:

答案 0 :(得分:3)

异步操作没有确定的执行时间。

当你致电unlink时,它会要求操作系统删除该文件,但是当操作系统实际删除该文件时,它没有定义;它可能是一毫秒或一年后。

异步操作的全部意义在于,除非明确说明,否则它们不会相互依赖。

rename之后unlink发生,您必须像这样修改代码:

fs.unlink("/tmp/test.png", function (err) {
    if (err) {
        console.log("An error occured");
    } else {
        fs.rename("/tmp/image1.png", "/tmp/test.png", function (err) {
            if (err) {
                console.log("An error occured");
            } else {
                console.log("Done renaming");
            }
        });
    }
});

或者,使用fs函数的同步版本(注意这些将阻止正在执行的线程):

fs.unlinkSync("/tmp/test.png");
fs.renameSync("/tmp/image1.png", "/tmp/test.png");

还有async等库使异步代码看起来更好:

async.waterfall([
    fs.unlink.bind(null, "/tmp/test.png");
    fs.rename.bind(null, "/tmp/image1.png", "/tmp/test.png");
], function (err) {
    if (err) {
        console.log("An error occured");
    } else {
        console.log("done renaming");
    }
});

请注意,在所有示例中,错误处理都非常简化,以表示想法。

答案 1 :(得分:1)

如果查看Node.js的documentation,您会发现函数fs.unlink将回调作为参数:

 fs.unlink(path, [callback]);

当前函数返回时要执行的操作应作为回调参数传递给函数。因此,通常在您的情况下,代码将采用以下形式:

 var fs = require("fs");
 fs.unlink("/tmp/test.png", function(){
     fs.rename("/tmp/image1.png", "/tmp/test.png");
 });

在unlink和rename的特定情况下,Node.js中也有同步函数,可以用作fs.unlinkSync(path)和fs.renameSync(oldPath,newPath)。这将确保代码同步运行。

此外,如果您希望使用异步实现但保留更好的可读性,则可以考虑使用async之类的库。它还具有不同实现模式的选项,如并行,系列,瀑布等。

希望这有帮助。