Javascript 都是节点“;“回调”;函数可能是异步的?
我是一个(相对而言)进入系统的节点新手,社区中对“只需编写回调,一切都是异步和事件驱动的,不用担心!”的热情让我对单个程序中的控制流感到有点困惑(或者更详细地说,在较大程序中处理单个请求期间的控制流) 如果在节点下运行以下程序Javascript 都是节点“;“回调”;函数可能是异步的?,javascript,node.js,callback,Javascript,Node.js,Callback,我是一个(相对而言)进入系统的节点新手,社区中对“只需编写回调,一切都是异步和事件驱动的,不用担心!”的热情让我对单个程序中的控制流感到有点困惑(或者更详细地说,在较大程序中处理单个请求期间的控制流) 如果在节点下运行以下程序 var foo = function(){ console.log("Called Foo"); }; var bar = function(){ console.log("Called Bar"); }; var doTheThing = funct
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();
是否有foo
在bar
之后执行的可能性?当我在本地通过命令行运行程序时,它总是
Called Foo
Called Bar
但是我看到很多善意的布道者的警告,比如不要假设你的回调会在你认为会被调用的时候被调用,我不清楚他们是在警告我库的实现细节,还是node.js在你使用函数对象作为参数时做了一些奇怪/特殊的事情。否
您的示例代码是100%同步、单线程、简单的自上而下的。但这是因为您不做任何I/O、没有任何真正的异步调用,也不使用进程。nextTick
、setTimeout
或setInterval
。要更真实地模拟异步调用,请执行以下操作:
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);
运行几次,您有时会看到无序的结果。否
您的示例代码是100%同步、单线程、简单的自上而下的。但这是因为您不做任何I/O、没有任何真正的异步调用,也不使用进程。nextTick
、setTimeout
或setInterval
。要更真实地模拟异步调用,请执行以下操作:
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);
运行几次,您有时会看到无序的结果。不,不可能。不适用于该代码 如果您正在编写自己的函数,或者如果您有权访问代码,则无需假设,您知道所有内容是否都是同步的,但是如果您没有权限访问代码,或者尚未阅读代码,则不可以假设回调将是同步的
然而,出于两个原因做出这样的假设是不好的做法,第一个原因是,仅仅因为它现在是同步的,并不意味着其他人或健忘的未来你以后不能改变它,第二个原因是,如果它都是同步的,为什么你/他们首先要使用回调?回调的整个要点是允许异步调用的可能性。使用回调,然后表现得好像它们总是同步的,即使你知道是这样,也会让你的代码让其他人感到困惑。不,不可能。不可能 如果您正在编写自己的函数,或者如果您有权访问代码,则无需假设,您知道所有内容是否都是同步的,但是如果您没有权限访问代码,或者尚未阅读代码,则不可以假设回调将是同步的 然而,出于两个原因做出这样的假设是不好的做法,第一个原因是,仅仅因为它现在是同步的,并不意味着其他人或健忘的未来你以后不能改变它,第二个原因是,如果它都是同步的,为什么你/他们首先要使用回调?回调的整个要点是允许异步调用的可能性。使用回调,然后表现得好像它们总是同步的,即使你知道是这样,也会让你的代码让其他人感到困惑 foo有没有可能在酒吧后被处决 在您当前的代码中,不是。尽管您的
doTheThing
函数具有异步函数签名(即,它将回调作为最后一个参数,对于不了解函数实现的外部人员来说,这表明它是异步的),它实际上是完全同步的,回调
将被调用,而不会屈服于运行时
然而
你真的没有理由给你的doTheThing
代码一个异步签名,除非你愿意在某个时候把真正的异步行为引入doTheThing
。在这一点上,你有一个问题,因为调用foo
和bar
的顺序会颠倒
在我看来,像您这样编写代码的好方法只有两种:要么将设置为同步(最重要的是:它不会依赖于I/O),这意味着您可以简单地从函数返回:
doTheThing = function(arg1){
return null
};
doTheThing()
foo()
bar()
或者直接更改doTheThing
的存根实现,以包括对setImmediate
的调用,即
var doTheThing = function(arg1, callback){
setImmediate(function() { callback(); );
};
注意,这也可以写成
var doTheThing = function(arg1, callback){
setImmediate(callback);
};
但这只是因为此时,回调不接受任何参数。第一个版本更接近于您所拥有的
一旦您这样做,bar
将始终在foo
之前被调用,现在可以安全地将异步功能引入doTheThing
foo有没有可能在酒吧后被处决
在您当前的代码中,不是。尽管您的doTheThing
函数具有异步函数签名(即,它将回调作为最后一个参数,对于不了解函数实现的外部人员来说,这表明它是异步的),它实际上是完全同步的,回调
将被调用,而不会屈服于运行时
然而
你真的没有理由给你的doTheThing
代码一个异步签名,除非你愿意在某个时候把真正的异步行为引入doTheThing
。在这一点上,你有一个问题,因为调用foo
和bar
的顺序会颠倒
在我看来,只有tw