一尘不染

异步Javascript执行如何发生?什么时候不使用return语句?

javascript

// 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()在从数据库中获取结果之后执行,而在异步代码中,console.log()在db.get()获取结果之前执行。

现在我的问题是,异步代码在后台如何执行?为什么非阻塞呢?

我搜索了Ecmascript 5标准,以了解异步代码的工作原理,但在整个标准中找不到异步一词。

从nodebeginner.org上,我还发现我们不应该使用return语句,因为它会阻塞事件循环。但是nodejs
api和第三方模块到处都包含return语句。那么什么时候应该使用return语句,什么时候不应该使用它?

有人可以对此有所启发吗?


阅读 546

收藏
2020-05-01

共1个答案

一尘不染

首先,将函数作为参数传递就是告诉您正在调用的函数,希望将来某个时候调用该函数。确切的将来何时调用该函数取决于函数正在执行的操作的性质。

如果该函数正在进行一些联网,并且该函数配置为非阻塞或异步,则该函数将执行,将开始联网操作,并且您调用的函数将立即返回,而其余的内联javascript代码将在返回之后该功能将执行。如果从该函数返回一个值,则该值将立即返回,很早在调用作为参数传递的函数之前(联网操作尚未完成)。

同时,网络操作正在后台进行。它正在发送请求,侦听响应,然后收集响应。当网络请求完成并且已收集响应时,然后,然后您调用的原始函数将调用您作为参数传递的函数。这可能只是几毫秒后,也可能是几分钟后,这取决于网络操作完成的时间。

重要的是要理解,在您的示例中,db.get()函数调用已经完成很长时间了,执行完之后的代码也依次执行。尚未完成的是您作为参数传递给该函数的内部匿名函数。这一直保存在javascript函数闭包中,直到以后网络功能结束。

我认为,使很多人感到困惑的一件事是,匿名函数在您对db.get的调用中声明,并且似乎是该函数的一部分,并且当db.get()完成后似乎也会这样做,但这就是并非如此。如果以这种方式表示,则可能看起来不太像:

function getCompletionfunction(result) {
    // do something with the result of db.get
}

// asynchronous Javascript 
db.get('select * from table1', getCompletionFunction);

然后,也许更明显的是db.get将立即返回,并且getCompletionFunction将在将来的某个时间被调用。我不建议您以这种方式编写它,而只是显示此表单以说明实际情况。

这是一个值得理解的序列:

console.log("a");
db.get('select * from table1', function(result){
    console.log("b");
});
console.log("c");

您将在调试器控制台中看到以下内容:

a
c
b

“ a”首先发生。然后,db.get()开始其操作,然后立即返回。因此,“
c”接下来发生。然后,当db.get()操作实际上在将来的某个时间完成时,就会发生“ b”。


2020-05-01