Javascript Node.js的同步与异步代码

Javascript Node.js的同步与异步代码,javascript,node.js,Javascript,Node.js,我们正在与node合作,主要是为了一个内部项目,并了解使用该技术的最佳方式 不是来自特定的异步背景,学习曲线可能是一个挑战,但我们正在习惯框架并学习过程 使我们两极分化的一件事是,使用同步代码与异步代码的最佳时间是什么时候。我们目前使用的规则是,如果任何东西与IO交互,那么它必须通过回调或事件发射器(这是给定的)实现异步,但其他不以任何方式使用IO的项可以构造为同步函数(这也取决于函数本身的重量和实际阻塞的程度)但是,这是使用Node.js时最好的方法吗 例如,我们正在创建一个Hal+JSON构

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

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

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

例如,我们正在创建一个Hal+JSON构建器,它目前存在于我们的代码库中。它是同步的,只是因为它所做的只是创建一些非常小的对象文本,除此之外,没有外部依赖关系,当然也没有IO交互


我们的方法是否合适?

假设您有两个同步执行的函数,
foo
bar

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活动或调用一些其他异步函数,那么您也需要更改
bar
的API

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

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

当然,如果某些操作非常快,那么就不需要异步代码。例如,考虑这个代码:

var arr = []; // assume array is nonempty
for (var i = 0, l = arr.length; i < l; i++) {
    arr[ i ].doStuff( );
}
现在这段代码是真正的异步代码。完成这项工作需要更多的时间,但同时它不会阻塞整个服务器。我们以性能换取响应能力


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

使用process.nextTick()将同步函数转换为异步函数是一个选项,但只有在软件阻塞时间过长时才应使用该选项。每次同步函数运行时,节点都无法执行任何其他操作,因为它是单线程的。这意味着,如果您的应用程序是服务器,它将变得无响应

在分解任何同步函数之前,我建议您首先进行一些基准测试和分析,以便做出明智的决策。否则,您将面临过早优化的风险

请参阅此处以进行良好的讨论


下面是如何使函数异步的,即允许node做其他事情

该应用程序是一个使用超媒体API的应用程序,我们使用HAL+JSON作为类型,因此我们需要一些东西来构建响应,它听起来比它更奇特。我们想做的不是在必须之前进行优化,甚至在没有保证的情况下构建一种风格,所以我们总是希望异步一些很重或IO受限的东西(现在或将来),但是对于更小、更快、永远没有IO的操作,我们可以安全地将它们作为同步代码输出。我认为这已经接近我们现在的水平了,使用synchronous完成较小的项目,而将异步内容留给I/O绑定的项目。我认为在我们的构建器示例中,同步是有意义的,因为它不涉及I/O,并且当前是内部的,但是如果我们决定将它移动到一个单独的模块中,我们可能会使它异步,以便其他像这样工作的人可以这样使用它。如上所述,这向我证实了我们的想法(以及其他一些答案)至少在正确的轨道上。是的,除非您处理的是网络或I/O等,否则不要使用CPS样式(异步样式)。uhh,您的第二个函数
bar
不是异步的。它使用回调,但仍然是同步的。就像
array.forEach()
使用回调一样,但仍然是同步的。我不知道这是怎么以如此多的选票被接受的答案。这是错误的。@jfriend00谢谢您的反馈。如果您阅读代码示例正下方的下一句话,您会看到它确切地说:“但事实是,这段代码仍然是完全同步的[…]”
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( );