【问题标题】:Synchronous vs Asynchronous code with Node.js使用 Node.js 的同步与异步代码
【发布时间】:2012-12-13 20:09:37
【问题描述】:

我们正在与 node 合作,主要是为了一个内部项目并了解使用该技术的最佳方式。

不是来自特定的异步背景,学习曲线可能是一个挑战,但我们正在习惯该框架并学习该过程。

让我们两极分化的一件事是,何时是使用同步代码与异步代码的最佳时机。我们目前使用的规则是,如果有任何东西与 IO 交互,那么它必须通过回调或事件发射器(这是给定的)异步的,但其他不以任何方式使用 IO 的项目可以构造为同步函数(这will 也取决于函数本身的重量以及它实际上是如何阻塞的)但这是使用 Node.js 时采用的最佳方法吗?

例如,我们正在创建一个 Hal+JSON 构建器,它当前存在于我们的代码库中。它是同步的,因为它所做的只是创建一些相当小的对象文字,仅此而已,没有外部依赖项,当然也没有 IO 交互。

我们的方法好不好?

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    假设您有两个函数,foobar,它们正在同步执行:

    function foo() {
        var returnValue = bar();
        console.log(returnValue);
    }
    
    function bar() {
        return "bar";
    }
    

    为了使API“异步”是改变它使用回调:

    function foo() {
        bar(function(returnValue) {
            console.log(returnValue);
        });
    }
    
    function bar(callback) {
        callback("bar");
    }
    

    但事实上,这段代码仍然是完全同步的。回调在同一个调用堆栈上执行,并且没有进行线程优化,没有可伸缩性优势。

    这就变成了代码可读性和编码风格的问题。我个人发现典型的var val = func(); 类型代码更具可读性和易理解性。唯一的缺点是,如果有一天你需要更改bar 的功能,那么它需要执行一些 I/O 活动或调用一些其他异步函数,你需要更改 @ 的 API 987654327@也是。

    我的个人偏好:在适用时使用传统的同步模式。当涉及 I/O 或有疑问时,请始终使用异步样式。

    【讨论】:

    • 我认为这与我们现在的情况很接近,使用同步来处理较小的项目,并将异步的东西留给 I/O 绑定项目。我也认为在我们的构建器示例中,目前同步是有意义的,因为它不涉及 I/O 并且当前是内部的,但是如果我们决定将它移动到一个单独的模块中,我们可能会使其异步所以其他像那样工作的人可以以这种方式使用它。
    • 与上述一样,这向我证实了我们的想法至少在正确的轨道上(以及其他一些答案)
    • 是的,除非你在处理网络或 I/O 等问题,否则不要理会 CPS 风格(异步风格)。
    • 呃,你的第二个函数bar 不是异步的。它使用回调,但它仍然是同步的。就像array.forEach() 使用回调一样,但仍然是同步的。不知道这如何成为有这么多赞成票的公认答案。错了。
    • @jfriend00 感谢您的反馈。如果您阅读代码示例正下方的下一句,您会看到它准确地说:“但事实是,这段代码仍然是完全同步的 [...]”
    【解决方案2】:

    使用 process.nextTick() 将同步函数转换为异步函数是一种选择,但仅当您的软件阻塞时间过长时才应使用该函数。每次同步函数运行时,节点都不能做任何其他事情,因为它是单线程的。这意味着,如果您的应用程序是服务器,它将变得无响应。

    在拆分任何同步函数之前,我建议先进行一些基准测试和分析,以便做出明智的决定。否则你会冒着过早优化的风险

    请参阅此处进行精彩讨论https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil

    这里是你如何让你的函数异步的,你将允许节点做其他事情http://howtonode.org/understanding-process-next-tick

    【讨论】:

      【解决方案3】:

      我不知道什么是“Hal+Json builder”,但这是我对 NodeJS 的看法。您应该尽可能异步地编写代码,将其推向极限。原因很简单,异步代码以性能换取响应能力,这在大多数情况下更为重要。

      当然,如果某些操作真的很快,那么就不需要异步代码。例如考虑以下代码:

      var arr = []; // assume array is nonempty
      for (var i = 0, l = arr.length; i < l; i++) {
          arr[ i ].doStuff( );
      }
      

      如果arr 很小,而doStuff 是一个快速操作,那么您不应该费心以异步方式编写此代码。但是,如果需要一些时间,那么您应该考虑这样写:

      var arr = []; // assume array is nonempty
      var process_array_element = function( ) {
          if (arr.length) {
              arr.pop().doStuff( );
              process.nextTick( process_array_element );
          }
      };
      process_array_element( );
      

      现在这段代码是真正异步的。它需要更多时间才能完成这项工作,但同时它不会阻塞整个服务器。我们以性能换取响应能力。

      结论:这取决于你的情况! :)

      【讨论】:

      • 应用程序是一个使用超媒体 API 的应用程序,我们使用 HAL+JSON 作为类型,所以我们需要一些东西来构建响应,这听起来更棒。我们想要做的不是在必须优化之前进行优化,甚至在没有保证的情况下构建一个样式,所以我们总是会寻找 Async 一些重的或 IO 绑定的东西(现在或将来可能),但是为了更小、更快、永远不会有 IO 操作,我们可以安全地将它们作为同步代码抽出。
      猜你喜欢
      • 2015-02-23
      • 1970-01-01
      • 2018-12-06
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      • 2013-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多