2

我有一个非常简单的实用程序脚本,我用 JavaScript 为 node.js 编写了它,它读取一个文件,进行一些计算,然后写入一个输出文件。当前形式的源代码如下所示:

fs.readFile(inputPath, function (err, data) {
    if (err) throw err;
    // do something with the data
    fs.writeFile(outputPath, output, function (err) {
        if (err) throw err;
        console.log("File successfully written.");
    });
});

这很好用,但我想知道在这种情况下使用这些函数的同步种类是否有任何缺点,如下所示:

var data = fs.readFileSync(inputPath);
// do something with the data
fs.writeFileSync(outputPath, output);
console.log("File successfully written.");

对我来说,这比回调类型更容易阅读和理解。在这种情况下是否有任何理由使用前一种方法?

我意识到对于我在本地运行的这个简单脚本,速度根本不是问题,但我有兴趣了解它背后的理论。什么时候使用异步方法有帮助,什么时候没有?即使在生产应用程序中,如果我只是读取一个文件,然后等待执行下一个任务,是否有任何理由使用异步方法?

4

2 回答 2

7

重要的是您的节点进程在同步 IO 发生时需要做什么。对于由单个用户在命令行运行的简单 shell 脚本,同步 IO 完全没问题,因为如果您正在执行异步 IO,那么您所做的就是等待 IO 无论如何返回。

但是,在具有多个用户的网络服务中,您永远不能使用任何同步 IO 调用(这是节点的全部意义,所以当我这样说时相信我)。这样做将导致所有连接的客户端停止处理,这是完全的厄运。

经验法则:shell 脚本:OK,网络服务:verboten!

为了进一步阅读,我在这个答案中做了几个类比。

基本上,当节点在网络服务器中进行异步 IO 时,它可以要求操作系统做很多事情:读取一些文件,进行一些数据库查询,发送一些网络流量,并在等待异步 IO 准备好时,它可以在主事件线程中做内存/CPU的事情。使用这种架构,节点可以获得相当好的性能/并发性。但是,当发生同步 IO 操作时,整个节点进程只是阻塞,完全什么都不做。它只是等待。无法接收到新的连接。没有处理发生,没有事件循环滴答,没有回调,什么都没有。仅 1 个同步操作就会为所有客户端停止整个服务器。你根本不能这样做。不管它有多快或类似的东西。本地文件系统或网络请求无关紧要。

于 2013-05-30T03:31:07.783 回答
1

异步代码不会阻塞执行流程,允许您的程序在等待操作完成时执行其他任务。

在第一个示例中,您的代码可以继续运行而无需等待文件被写入。在您的第二个示例中,代码执行被“阻止”,直到文件被写入。这就是为什么同步代码被称为“阻塞”而异步被称为“非阻塞”的原因。

于 2013-05-30T03:32:15.400 回答