简体   繁体   English

所有节点“回调”功能都可能是异步的吗?

[英]Are All Node “callback” Functions Potentially Asynchronous?

I'm a (relative) node newbie getting in the system, and all the enthusiasm in the community for "just write callbacks, everything's asynchronous and event driven, don't worry!" 我是进入系统的(相对)节点新手,并且社区中的所有热情“只需编写回调,所有内容都是异步的并且是事件驱动的,不用担心!” has left me a little confused as to the control flow within a single program (or in more node-ish terms, the control flow during the handling of a single request in a larger program) 使我对单个程序中的控制流有些困惑(或更笼统地说,是在较大程序中处理单个请求期间的控制流)

If I have the following program running under node 如果我在节点下运行以下程序

var foo = function(){
    console.log("Called Foo");
};

var bar = function(){
    console.log("Called Bar");
};

var doTheThing = function(arg1, callback){
    callback();
};

doTheThing(true, function() {
    foo();
});
bar();

Is there any chance that foo will execute after bar ? 是否有任何机会, foo执行bar When I run the program via the command line locally, it's always 当我通过命令行在本地运行程序时,总是

Called Foo
Called Bar

but I see so many warnings from well intended evangelists along the lines of don't assume your callback will be called when you think it will , that I'm unclear if they're just warning me about library implementation details, or if node.js does something weird/special when you use a function object as parameter. 但是我看到好主意的福音派人士发出了许多警告,包括不要假设您认为回调会被调用 ,我不清楚他们是否只是在警告我有关库实现的详细信息或节点。当您使用函数对象作为参数时,js会做一些奇怪的/特殊的事情。

No, there's no chance. 不,没有机会。 Not for that code. 不适用于该代码。

If you're writing your own functions, or if you have access to the code, you don't need to assume, you know whether everything's synchronous or otherwise, but if you don't have access to the code, or haven't yet read it, then no, you can't assume callbacks are going to be synchronous. 如果您正在编写自己的函数,或者可以访问代码,则无需假设一切都是同步的,而是如果您无法访问代码或没有权限,则可以。尚未阅读,那么不行,您不能假设回调将是同步的。

It's however bad practice to make assumptions like that for two reasons, first is that just because it's synchronous now doesn't mean somebody else, or forgetful future you can't change it later, and secondly, because if it's all synchronous, why are you/they using callbacks in the first place? 但是,进行这样的假设是不好的做法 ,原因有两个,首先是仅仅因为它现在是同步的,就不意味着其他人,或者健忘的未来您以后不能更改它,其次,因为如果它们都是同步的,为什么您/他们是否首先使用回调? The entire point of callbacks is to allow for the possibility of asynchronous calls. 回调的全部要点是允许异步调用的可能性。 Using callbacks and then acting like they're always going to be synchronous, even if you know that's the case, makes your code confusing for anybody else coming in. 使用回调,然后像使它们始终保持同步一样工作,即使您知道这种情况,也会使您的代码对其他任何人造成混乱。

No 没有

Your sample code is 100% synchronous, single-threaded, simple top-to-bottom. 您的示例代码是100%同步,单线程,简单的从上到下。 But that's because you don't do any I/O, don't have any real asynchronous calls, and don't use process.nextTick , setTimeout , or setInterval . 但这是因为您不执行任何I / O,没有任何真正的异步调用,并且不使用process.nextTicksetTimeoutsetInterval To more realistically simulate async calls do something like: 要更实际地模拟异步调用,请执行以下操作:

function fakeAsync(name, callback) {
  setTimeout(function () {
    callback(null, name);
  }, Math.random() * 5000);
}

function logIt(error, result) {
  console.log(result);
}

fakeAsync('one', logIt);
fakeAsync('two', logIt);
fakeAsync('three', logIt);

Run that a few times and you'll see out-of-order results sometimes. 运行几次,有时会看到乱序的结果。

Is there any chance that foo will execute after bar? foo在bar之后执行是否有可能?

In your current code, no. 在您当前的代码中,没有。 Although your doTheThing function has an asynchronous function signature (ie it takes a callback as the last argument, which to an outsider with no knowledge about the function's implementation would suggest that it's asynchronous), it's actually fully synchronous, and callback will be called without yielding to the runtime. 尽管您的doTheThing函数具有异步函数签名(即,将回调作为最后一个参数,对不知道该函数实现的局外人来说,这表明它是异步的),但它实际上是完全同步的,并且将在不产生callback情况下调用callback到运行时。

However 然而

You really have no reason to give your doTheThing code an asynchronous signature, unless you're accommodating for introducing real async behavior into doTheThing at some point. 您确实没有理由为您的doTheThing代码提供一个异步签名, 除非doTheThing在某个时候将真正的异步行为引入doTheThing中。 And at that point, you have a problem, because the order in which foo and bar are called will flip. 到那时,您遇到了问题,因为foobar的调用顺序将翻转。

In my opinion, there are only two good ways of writing code like you do: Either make it set in stone that doTheThing will be synchronous (most importantly: that it won't be dependent on I/O), which means that you can simply return from the function: 在我看来,只有两种写代码的好方法,就像您做的那样:要么将doTheThing设置为同步(最重要的是:它将不依赖于I / O),这意味着您可以只需从函数返回:

doTheThing = function(arg1){
   return null
};
doTheThing()
foo()
bar()

or change the stub implementation of doTheThing directly to include a call to setImmediate , ie 或直接更改doTheThing的存根实现以包含对setImmediate的调用,即

var doTheThing = function(arg1, callback){
   setImmediate(function() { callback(); );
};

Note that this can also be written as 请注意,这也可以写成

var doTheThing = function(arg1, callback){
   setImmediate(callback);
};

but that's just because at this moment, callback does not take any arguments. 但这仅仅是因为此时,回调不接受任何参数。 The first version is more close to what you had. 第一个版本更接近于您所拥有的版本。

As soon as you do this, bar will always be called before foo , and it has now become safe to introduce async functionality into doTheThing . 一旦执行此操作, bar将始终在foo之前被调用,现在已经可以安全地在doTheThing引入异步功能了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM