包装 node.js 同步函数是不是使其执行与其等效的异步相同?

Posted

技术标签:

【中文标题】包装 node.js 同步函数是不是使其执行与其等效的异步相同?【英文标题】:Does wrapping a node.js sync function make it perform the same as its async equivalent?包装 node.js 同步函数是否使其执行与其等效的异步相同? 【发布时间】:2015-11-28 14:07:20 【问题描述】:

没有错误处理的简单示例:

var fs = require('fs');

function read(filename, cb) 
  return cb(fs.readFileSync(filename));

就事件循环而言,这在性能方面是否相同,如:

fs.readFile(filename, cb);

我问的原因是加密库中的一些异步函数仍然会抛出错误,而不是将它们传递给回调。我只想制作一个自定义异步函数,以我想要的方式进行错误处理,但我担心使用本机方法的同步版本,因为它们在节点社区中因性能不佳而声名狼藉。那么,按照我建议的方式来做一个包装函数是否安全?

【问题讨论】:

为什么你认为这样更好? ...它仍然是同步的,只是多了一个函数调用。 @SLaks 我希望做一些自定义错误处理,而不是依赖本机库的方式。但是,它看起来不像我所希望的那样,所以我仍然需要依赖本机异步方法。 @SebastianSandqvist:您可以包装原生 async 库并添加自己的错误处理。 @SebastianSandqvist:不;您可以简单地传递一个回调并检查错误参数。如果你包装了一个异步方法,你可以传递一个检查错误的回调,然后调用你自己的回调。 【参考方案1】:

没有。

异步的全部意义在于,由readFileSync() 完成的实际工作发生在事件循环之外

调用同步函数并使其异步是完全不可能的。

【讨论】:

setImmediatesetTimeout 封装包装器怎么样,还是不好? @renatoargh 这只是在同步操作发生时延迟。【参考方案2】:

您不能以任何方式使异步函数突然在本机 node.js 中同步运行(例如,不创建另一个进程或使用执行某些线程的第三方库)。就是做不到。

这对你一点帮助都没有:

function read(filename, cb) 
  return cb(fs.readFileSync(filename));

它只是实现了一个同步回调,并没有真正解决任何问题。代码仍然是同步的,因此您无法获得异步 I/O 的任何好处。您在这里获得的重要异步 I/O 好处是您希望主 JS 事件循环不等待文件 I/O 发生。当文件 I/O 在本机代码中发生时,您希望 node.js 事件循环能够执行其他操作。只要您使用fs.readyFileSync(),就永远不会出现这种情况,无论您使用什么。


如果您有一些异步加密方法同步抛出异常而不是将错误传递给它们的回调,那是设计不佳的代码,我什至会三思而后行。

但是,您可以通过将加密函数包装在自己的 try catch 处理程序中来解决此问题,如果抛出错误,该处理程序将调用回调。

假设你有一个这样的加密函数:

function badCryptoFunc(arg1, arg2, callback)

你可以这样换行:

function myCryptoFunc(arg1, arg2, callback) 
    try 
        badCryptoFunc(arg1, arg2, callback);
     catch(e) 
        callback(e);
    

如果函数异步抛出,那么即使这样也不会捕获异常,并且代码很糟糕并且不能安全使用,因为在大多数情况下,在系统调用异步异常之前无法捕获它,而不是您的代码。

【讨论】:

You cannot in any way make an asynchronous function suddenly behave synchronously in node.js -- 好吧,你可以使用meteor.js 框架大量使用的纤维。但我不是很喜欢这种风格。至于反过来,你可以使用 webworkers 使同步函数异步。 @slebetman - 好吧,有点像第三方库运行不同的线程。如果你想获得技术,你可以启动一个不同的 nodejs 进程并在那里运行你想要的任何东西,这可能与原始进程“异步”,但这些都不是 OP 要求或试图做的。 webworkers 无疑是 OP 试图做的事情的解决方案。事实上,这就是它的设计目的。您可以通过创造性地使用 ChildProcess 生成 REPL 来模拟 web worker,但由于已经有很多好的 webworker 实现,只需从 npm 中获取一个。与一些较旧的线程模块相比,Web Worker 的好处在于其知识可以转移到浏览器中。 @slebetman - 我希望您能在 node.js 中使用 webWorkers 显示答案,让 OP 的代码真正起作用。而且,如果目标是不阻塞事件循环,为什么不首先使用异步readFile()?我很好奇您如何进行不阻塞事件循环的同步调用,因为这似乎是 OP 所要求的。 @jfriend00 我在这里使用readFile() 只是一个随意的例子。我想这样做的真正原因是我发现节点的crypto async pbkdf2 函数在某些情况下会抛出,而不是将错误传递给回调的第一个参数。我在想我可以为同步方法制作一个包装器,但基于这些答案,这看起来不是一个好的选择。

以上是关于包装 node.js 同步函数是不是使其执行与其等效的异步相同?的主要内容,如果未能解决你的问题,请参考以下文章

node.js中的forEach是同步还是异步

在 node.js 中导入 sql 文件并针对 PostgreSQL 执行

在 Node.js 和 v8 中调用使用包装对象作为参数的函数

Node.js - File System

同步和异步 以及node js 回调函数

node.js 回调函数事件循环EventEmitter ar