我想知道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
可能会先执行,导致错误。
答案 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之类的库。它还具有不同实现模式的选项,如并行,系列,瀑布等。
希望这有帮助。