异步 Javascript 执行是如何发生的?什么时候不使用return语句?
// synchronous Javascript
var result = db.get('select * from table1');
console.log('I am syncronous');
// asynchronous Javascript
db.get('select * from table1', function(result){
// do something with the result
});
console.log('I am asynchronous')
我知道在同步代码中,console.log() 在从 db 获取结果之后执行,而在异步代码中,console.log() 在 db.get() 获取结果之前执行.
I know in synchronous code, console.log() executes after result is fetched from db, whereas in asynchronous code console.log() executes before the db.get() fetches the result.
现在我的问题是,异步代码的执行是如何在后台发生的,为什么它是非阻塞的?
Now my question is, how does the execution happen behind the scenes for asynchronous code and why is it non-blocking?
我搜索了 Ecmascript 5 标准以了解异步代码的工作原理,但在整个标准中找不到异步这个词.
I have searched the Ecmascript 5 standard to understand how asynchronous code works but could not find the word asynchronous in the entire standard.
从 nodebeginner.org 我还发现我们不应该使用 return 语句,因为它会阻塞事件循环.但是 nodejs api 和第三方模块到处都包含 return 语句.那么什么时候应该使用 return 语句,什么时候不应该呢?
And from nodebeginner.org I also found out that we should not use a return statement as it blocks the event loop. But nodejs api and third party modules contain return statements everywhere. So when should a return statement be used and when shouldn't it?
有人可以解释一下吗?
推荐答案
首先,将函数作为参数传递是告诉函数你正在调用你希望它在未来的某个时间调用这个函数.未来何时调用它取决于函数正在执行的操作的性质.
First of all, passing a function as a parameter is telling the function that you're calling that you would like it to call this function some time in the future. When exactly in the future it will get called depends upon the nature of what the function is doing.
如果该函数正在做一些联网并且该函数被配置为非阻塞或异步,那么该函数将执行,联网操作将启动,您调用的函数将立即返回,其余的内联该函数之后的javascript代码将执行.如果您从该函数返回一个值,它将立即返回,早在您作为参数传递的函数被调用之前(网络操作尚未完成).
If the function is doing some networking and the function is configured to be non-blocking or asychronous, then the function will execute, the networking operation will be started and the function you called will return right away and the rest of your inline javascript code after that function will execute. If you return a value from that function, it will return right away, long before the function you passed as a parameter has been called (the networking operation has not yet completed).
与此同时,网络操作正在后台进行.它发送请求,监听响应,然后收集响应.当网络请求完成并收集响应时,然后,您调用的原始函数才会调用您作为参数传递的函数.这可能仅在几毫秒之后,也可能在几分钟之后 - 取决于网络操作完成所需的时间.
Meanwhile, the networking operation is going in the background. It's sending the request, listening for the response, then gathering the response. When the networking request has completed and the response has been collected, THEN and only then does the original function you called call the function you passed as a parameter. This may be only a few milliseconds later or it may be as long as minutes later - depending upon how long the networking operation took to complete.
需要了解的重要一点是,在您的示例中,db.get()
函数调用早已完成,并且代码在它也已执行后按顺序执行.尚未完成的是您作为参数传递给该函数的内部匿名函数.它被保存在一个 javascript 函数闭包中,直到稍后网络函数完成.
What's important to understand is that in your example, the db.get()
function call has long since completed and the code sequentially after it has also executed. What has not completed is the internal anonymous function that you passed as a parameter to that function. That's being held in a javascript function closure until later when the networking function finishes.
我认为让很多人感到困惑的一件事是匿名函数是在您对 db.get 的调用中声明的,并且似乎是其中的一部分,并且当 db.get()
完成了,这也将完成,但事实并非如此.如果以这种方式表示,也许会看起来不那么像:
It's my opinion that one thing that confuses a lot of people is that the anonymous function is declared inside of your call to db.get and appears to be part of that and appears that when db.get()
is done, this would be done too, but that is not the case. Perhaps that would look less like that if it was represented this way:
function getCompletionfunction(result) {
// do something with the result of db.get
}
// asynchronous Javascript
db.get('select * from table1', getCompletionFunction);
那么,也许更明显的是 db.get 将立即返回,而 getCompletionFunction 将在未来某个时间被调用.我不是建议你这样写,只是展示这个表格来说明实际发生的事情.
Then, maybe it would be more obvious that the db.get will return immediately and the getCompletionFunction will get called some time in the future. I'm not suggesting you write it this way, but just showing this form as a means of illustrating what is really happening.
这是一个值得理解的序列:
Here's a sequence worth understanding:
console.log("a");
db.get('select * from table1', function(result){
console.log("b");
});
console.log("c");
您将在调试器控制台中看到的是:
What you would see in the debugger console is this:
a
c
b
a"首先发生.然后,db.get() 开始它的操作,然后立即返回.因此,c"接下来发生.然后,当 db.get() 操作在未来某个时间实际完成时,会发生b".
"a" happens first. Then, db.get() starts its operation and then immediately returns. Thus, "c" happens next. Then, when the db.get() operation actually completes some time in the future, "b" happens.
有关异步处理如何在浏览器中工作的一些信息,请参阅 JavaScript 如何在后台处理 AJAX 响应?
For some reading on how async handling works in a browser, see How does JavaScript handle AJAX responses in the background?
相关文章