Node.js - 我啥时候应该做异步的事情,啥时候做同步
Posted
技术标签:
【中文标题】Node.js - 我啥时候应该做异步的事情,啥时候做同步【英文标题】:Node.js - when should I do things async and when syncNode.js - 我什么时候应该做异步的事情,什么时候做同步 【发布时间】:2012-06-28 20:59:00 【问题描述】:我对 node.js 的异步特性感到困惑。我正在其中编写一个小项目,而我之前的(同步)编程经验阻碍了我。
我应该如何决定是否/在哪里编写异步代码?
例如,我有一个带有字段的模型,其中每个都有一些验证规则:
model = title: text_validation,
subtitle: text_validation
text_validation = max_len: 10,
required: true,
url: true
当我验证模型时,我会遍历所有字段,检查规则是否通过 - 这些是非常快速的功能。
Model.validate = function()
validator = ;
fields = Object.keys(Model);
fields.forEach(function(field)
validator[field_name] = field.validate();
);
Field.validate = function()
validator = [];
rules.forEach(function(rule)
if (rule is not valid)
validator.push(rule)
);
return validator;
我应该使用具有如此短且快速迭代的回调吗?
这里的限制在哪里? node.js 应该始终是异步的,或者如果它足够快,我可以允许同步循环或 w/e 吗?如果可能,请参考何时何地使用同步/异步的示例。
【问题讨论】:
使用回调不是与异步是一回事。制作一个简单的异步循环并不是一件容易的事(请看process.nextTick
),而且在大多数情况下,这样做确实没有明显的优势。除非你的循环需要 真的 很长时间。
感谢您的回答。真的很长时间是什么意思? ;)
其实我也不知道。 :) 我从来没有遇到过这么长时间的麻烦。
如果你真的能注意到,那就太长了。
【参考方案1】:
你可能不应该。在大多数情况下,只有在等待应用程序外部的某些内容(主要是文件、数据库和网络操作)时才需要异步逻辑。异步延迟应用程序内代码不会给您带来任何性能优势,因为您的代码仍需要在某个时间点运行。
【讨论】:
这与性能无关。这是关于高可用性的。如果循环需要很长时间,那么所有其他用户都在等待(服务器基本上被阻塞)。使其异步允许其他用户与服务器交互。当然要付出代价:循环将花费更多时间。 如果循环花费了太多时间(即计算量很大),您可以将fork it 放入一个单独的进程并通过child.send()
传递其结果。除此之外,将循环分解为异步迭代将过于复杂。【参考方案2】:
我已经在评论中说过了,但我认为举个例子也是个好主意。
回调和异步操作的概念是不同的,虽然是相关的。您正在使用的forEach
循环根本不是异步的。以下是forEach
的定义或多或少的样子:
Array.prototype.forEach = function(callback)
var l = this.length;
for (var i = 0; i < l; i++)
callback(this[i], i);
;
如您所见,其中没有任何异步内容。 callback
在循环中一步一步地同步执行。
那么如何使循环异步呢?好吧,你可以试试这个:
Array.prototype.asyncForEach = function(applier, finished)
var self = this;
var l = self.length;
var call = function(i)
process.nextTick(function()
applier(self[i], i);
if (i == l-1)
finished();
else
call(i+1);
);
call(0);
;
你可以这样使用它:
var x = [1,2,3,4,5,6,7,8,9,10];
x.asyncForEach(function(el, index)
/* apply function to each el and index */
console.log(el);
, function()
/* This will be called when the loop finishes! */
console.log('Finished!');
);
/* Let us check whether the loop is really asynchronous.
The following code should fire BEFORE loop! */
console.log('Is it asynchronous?');
如您所见,它不像forEach
那样简单明了。但这允许其他代码在循环的迭代之间运行(process.nextTick
方法的魔力)。所以你获得了High Availability,但代价是循环完成需要更多的时间。请注意,在迭代之间修改数组是可能的,它可能会导致您的应用程序崩溃。 :D
正如我在评论中所说:我从未见过一个循环工作这么长时间,以至于它实际上需要变成异步循环。而且我使用了一些我处理过很多的市场数据(尽管使用 Python,而不是 javascript——这可能是一个原因)。正如 lanzz 所评论的,如果循环花费了太多时间,那么分叉它可能是一个好主意。或者创建一个用某种高效语言 (C?) 编写的 WebService(或 Node.JS addon)。
【讨论】:
谢谢你,但我现在还有一些其他问题。据我了解:异步代码非常需要回调,因为我们希望事件循环在将来的某个地方启动它们(在我们的异步内容完成之后)。因此,如果我有一个阻塞的 foreach 循环,那么在其中执行异步操作不会解除线程阻塞,但是当我使用“异步”模块中的 forEach 并将 fs.readFile 放在那里时,它将是非阻塞的? @muchzill4 我刚刚查看了异步的forEach
源代码。看起来它的工作方式与我向您展示的代码有点不同。它为数组中的每个元素(在同步循环中)调用nextTick
,而不是调用nextTick
在上一个刻度完成工作之后。这意味着异步循环的任何两次迭代之间不能有任何代码,即异步的forEach
等待服务器完成所有其他“作业”(调用时其他定义的滴答声)并同步触发循环。至少在我看来是这样的。
现在你让我完全糊涂了。 async 的 forEach 在哪里调用 nextTick?你说的是和我一样的异步吗? github.com/caolan/async/blob/master/lib/async.js
起来,对不起。我只看了 1 秒(我当时正在工作,呵呵)不知何故我确定我在那里看到了nextTick
。但你是对的,那里没有异步的东西。然后这条线(在他们的主页上)since this function applies the iterator to each item in parallel there is no guarantee that the iterator functions will complete in order
是一个谎言。 O_o
我问过(你也可能?;)) async 的作者,他是这么说的:async.forEach is the same as forEach but it provides a mechanism to let you know when processing of the asynchronous tasks have completed (using callbacks). Using the standard forEach would run the functions in the same order, but would give you no indication of when they completed and whether an error occurred. async.forEach does not magically make synchronous code asynchronous. It's just a tool to help you keep track of asynchronous operations and manage when they run.
以上是关于Node.js - 我啥时候应该做异步的事情,啥时候做同步的主要内容,如果未能解决你的问题,请参考以下文章