node.js中的回调是始终异步还是始终同步?或者他们可以是#34;有时是一个,有时是另一个"?

时间:2015-08-11 14:37:51

标签: javascript node.js asynchronous callback

我想在node.js中制作东西,而我(就像其他开始学习节点的人一样)对它的异步性质有疑问。我搜索了一下,但无法找到关于它回答的具体问题(也许我只是没有搜索得很好......),所以这里有:

如果文档说明,那么node.js回调通常是保证是异步的吗?如果您创建自己的函数来进行回调,那么您是否应该以这样的方式进行设计,以使它们始终是异步的或始终是同步的?或者他们有时可能是同步的,有时候不是吗?

举个例子,假设您想通过互联网加载一些数据,并创建了一个加载它的功能。但是数据并不经常发生变化,因此您决定将其缓存以备将来调用。你可以想象有人会写这样的函数:

All available Azure Subscriptions are:

SubscriptionName
---------------- 
Visual Studio Premium with MSDN
--------------------------------------------- 
PS C:\Users\nissan\Documents\Azure>

其中fetchDataFromNetwork是一个异步执行其回调的函数(这有点伪代码,但我希望你理解我的意思)。

如果数据没有被缓存,这个函数只会异步激活,如果它被缓存,它只是直接执行回调。在这种情况下,功能的异步性质毕竟是完全没必要的。

这种事情是否气馁?该函数的第二行应该是function getData(callback) { if(dataIsCached) { callback(cachedData) } else { fetchDataFromNetwork(function (fetchedData) { dataIsCached = true; cachedData = fetchedData; callback(fetchedData); }); } } ,以保证它是异步触发的吗?

我问的原因是我在一段时间后看到了一些代码,其中回调中的代码只是假设回调之外的其余函数已经在回调内的代码之前执行了。我愣了一下,思考着#34;但你怎么知道回调会异步触发?如果它不需要同步执行怎么办?为什么你会假设每个回调都保证是异步的?"

对这一点的任何澄清将不胜感激。谢谢!

4 个答案:

答案 0 :(得分:3)

您的假设都是正确的。

  

一般来说,如果文档说明,那么node.js回调是否保证是异步的?

是。当然,有functions with async callbacks and functions with sync callbacks,但都没有。{/ p>

  

如果您创建自己的回调函数,那么您是否应该以这样的方式进行设计,以使它们始终是异步的或始终是同步的?

  

它们有时可能是同步的,有时候不是,例如缓存?这种事情气馁了吗?

是。 Very much d̲̭i̫̰̤̠͎͝ͅͅs͙̙̠c̙͖̗̜o͇̮̗̘͈̫ų̗͔̯ŕa҉̗͉͚͈͈̜g͕̳̱̗e҉̟̟̪͖̠̞ͅd͙͈͉̤̞̞̩

  

该函数的第二行应该是setTimeout(function () {callback(cachedData)}), 0),以保证它以异步方式触发吗?

是的,这是一个好主意,但在节点中,您宁愿使用setImmediate or process.nextTick代替setTimeout。 或者使用保证不同步的承诺,这样你就不必自己关心延迟事情了。

  

我在前面看到了一些代码,其中回调中的代码只是假设回调之外的其余函数已经在回调内的代码之前执行了。我稍微退缩了一下

是的,可以理解。即使您使用的API保证异步,编写代码仍然会更好,以便可以按照执行的顺序读取代码。如果可能,您应该放置在异步回调之前立即执行的事情(例外证明规则)。

答案 1 :(得分:1)

我个人同意你的观点,即在函数返回后永远不会假设异步代码执行(根据定义,异步只是意味着你不能假设它是同步的,而不是假设它不是同步的)。

但是有一种文化围绕javascript发展,它考虑了一种可以同步或异步反模式的功能。这是有道理的:如果你无法预测何时代码运行,那么就很难对其进行推理。

所以一般来说,所有流行的图书馆都避免使用它。一般来说,假设异步代码在脚本结束之前永远不会运行是非常安全的。

除非你有一个非常特殊的理由,否则不要写一个既可以同步又可以同步的函数 - 它被认为是一种反模式。

答案 2 :(得分:0)

你永远不应该有一个接受有时同步的回调的函数,这可能会导致你遇到尾递归问题。请看以下示例:

function doSynchronousWork (cb) {
    cb();
}
doSynchronousWork(function looper () {
   if (...somecondition...) {
       doSynchronousWork(looper);
   }
});

在上面的示例中,由于callstack嵌套太深,您将遇到最大callstack超出错误。强制同步函数异步运行通过在继续递归之前清除callstack来解决该问题。

function doSynchronousWork (cb) {
    process.nextTick(cb);
}
doSynchronousWork(function () {
   if (...somecondition...) {
       doSynchronousWork();
   }
});

请注意,此尾递归问题最终将在js引擎中修复

不要将回调与迭代器函数混淆

答案 3 :(得分:0)

你需要摆脱不需要异步的想法 - 在Node中需要同步,或者它应该是异步的另一种想法。

Async是Node.js背后的完整哲学,回调本质上是异步的(如果它们设计得当),它允许Node按照它声称的非阻塞。这就是假设回调将异步执行的假设 - 它是Node的设计理念的一个密切部分。

  

该函数的第二行是否应该是setTimeout(function(){callback(cachedData)}),0)而是为了保证它以异步方式触发?

在Node中,我们使用process.nextTick()来确保某些内容以异步方式运行,延迟它的功能,直到事件循环的下一个滴答。