Nodejs async&同步阅读&写文件 - 何时使用哪个?

时间:2017-09-22 16:28:17

标签: javascript node.js asynchronous

这是一个非常普遍的问题,但我不太明白。我什么时候比较喜欢一个?我似乎无法理解可能会出现什么情况,哪些情况明显支持另一种情况。是否有充分理由避免x /使用x?

2 个答案:

答案 0 :(得分:2)

  

我什么时候比较喜欢一个?

使用非Sync版本(异步版本),除非在I / O待处理时你的程序没有其它任何东西,在这种情况下,Sync版本没问题;请参阅下面的详细信息...

  

是否有充分理由避免x /使用x?

是。 NodeJS在单个线程上运行您的JavaScript代码。如果使用Sync版本的I / O函数,则该线程将在I / O上等待,并且无法执行任何其他操作。如果您使用异步版本,I / O可以在后台继续,而JavaScript线程继续其他工作; I / O完成将排队作为JavaScript线程的作业,以便稍后返回。

如果你正在运行一个前台节点应用程序,在I / O挂起时不需要做任何其他操作,那么你可能正好使用Sync个调用。但是,如果您使用Node一次处理多个事物(如Web请求),最好使用异步版本。

您在评论中添加了评论:

  

我想到了一个带有nodejs的电子应用程序,它只是简单地读取一个文件并且不明白会使真正的区别,如果我的软件真的只需要等待该文件加载

我几乎不了解Electron,但我注意到它使用“主”进程来管理窗口,然后每个窗口使用“渲染”进程(link)。在这种情况下,使用Sync函数将阻止相关过程,这可能会影响应用程序或窗口响应。但我对Electron没有任何深入的了解(更多的是遗憾)。

直到最近,使用异步函数意味着使用大量难以编写的回调代码:

// (Obviously this is just an example, you wouldn't actually read and write a file this way, you'd use streaming...)
fs.readFile("file1.txt", function(err, data) {
    if (err) {
        // Do something about the error...
    } else {
        fs.writeFile("file2.txt", data, function(err) {
            if (err) {
                // Do something about the error...
            } else {
                // All good
        });
    }
});

然后出现了承诺,如果你使用了一个promisified *版本的操作(这里显示的是fs.promisifiedXYZ等假名),它仍然涉及回调,但它们更易于组合:

// (See earlier caveat, just an example)
fs.promisifiedReadFile("file1.txt")
.then(function(data) {
    return fs.promisifiedWriteFile("file2.txt", data);
})
.then(function() {
    // All good
})
.catch(function(err) {
    // Do something about the error...
});

现在,在最新版本的Node中,您可以使用ES2017 + async / await语法编写看似同步的代码,实际上是异步代码:

// (See earlier caveat, just an example)
(async () => {
    try {
        const data = await fs.promisifiedReadFile("file1.txt");
        fs.promisifiedWriteFile("file2.txt", data);
        // All good
    } catch (err) {
        // Do something about the error...
    }
})();

Node的API早于promises并且有自己的约定。有各种各样的库可以帮助你“宣传”一个Node风格的回调API,以便它使用promises代替。一个是promisify,但还有其他人。

答案 1 :(得分:2)

  

我什么时候比较喜欢一个?

在旨在扩展和满足许多用户需求的服务器中,您只能在服务器初始化期间使用同步I / O.实际上,require()本身使用同步I / O.在服务器已经启动并运行时处理传入请求的服务器的所有其他部分中,您将只使用异步I / O.

除了创建服务器之外,node.js还有其他用途。例如,假设您要创建一个脚本,该脚本将解析一个巨大的文件并查找某些单词或短语。并且,此脚本旨在自行运行以处理一个文件,并且它没有持久的服务器功能,并且没有特别的理由同时从多个源执行I / O.在这种情况下,使用同步I / O是完全可以的。例如,我创建了一个node.js脚本,帮助我使备份文件老化(删除符合某些特定年龄标准的备份文件),并且我的计算机每天自动运行该脚本一次。没有理由对这种类型的使用使用异步I / O,所以我使用了同步I / O,它使代码更容易编写。

  

我似乎不明白可能会出现什么样的情况,这显然会偏向于另一种情况。是否有充分理由避免x /使用x?

避免在服务器的请求处理程序中使用同步I / O.由于node.js中Javascript的单线程特性,使用同步I / O阻塞node.js Javascript线程所以它一次只能做一件事(这对于多用户服务器是死亡)而异步I / O不会阻塞node.js Javascript线程(允许它可能满足许多​​用户的需求)。

在非多用户情况下(对一个用户只做一件事的代码),同步I / O可能会受到青睐,因为编写代码更容易,并且使用异步I / O可能没有任何优势。 / p>

  

我想到了一个带有nodejs的电子应用程序,它只是简单地读取一个文件并且不明白真正有什么区别,如果我的软件真的只需要等待该文件加载。

如果这是一个单独的用户应用程序,那么在等待文件被读入内存时,您的应用程序没有其他任何内容(没有套接字要响应,没有屏幕更新,没有其他请求可用,没有其他文件操作可以并行运行),那么使用异步I / O没有任何优势,因此同步I / O会很好,并且可能更容易编码。