首先,我意识到我回答这个问题晚了。
在讨论同步和异步之前,让我们简要地看看程序是如何运行的。
在同步情况下,每条语句在下一条语句运行之前完成。在这种情况下,程序完全按照语句的顺序进行评估。
这就是异步在 JavaScript 中的工作方式。JavaScript 引擎中有两部分,一部分查看代码并将操作排入队列,另一部分处理队列。队列处理发生在一个线程中,这就是为什么一次只能发生一个操作。
当看到异步操作(如第二个数据库查询)时,将解析代码并将操作放入队列,但在这种情况下,会注册回调以在此操作完成时运行。队列中可能已经有许多操作。队列前端的操作被处理并从队列中移除。处理完数据库查询的操作后,将请求发送到数据库,完成后将在完成时执行回调。此时,已“处理”该操作的队列处理器将继续进行下一个操作——在本例中
console.log("Hello World");
数据库查询仍在处理中,但 console.log 操作位于队列的前面并被处理。这是一个同步操作,立即执行,结果立即输出“Hello World”。一段时间后,数据库操作完成,才调用并处理向查询注册的回调,将变量结果的值设置为行。
一个异步操作可能会导致另一个异步操作,这第二个操作将被放入队列中,当它到达队列的前面时,它将被处理。调用异步操作注册的回调是 JavaScript 运行时在操作完成时返回操作结果的方式。
了解哪个 JavaScript 操作是异步的一个简单方法是注意它是否需要回调 - 回调是第一个操作完成时将执行的代码。在题中的两个例子中,我们可以看到只有第二种情况有回调,所以是两者的异步操作。由于处理异步操作的结果的方式不同,情况并非总是如此。
要了解更多信息,请阅读 Promise。Promise 是另一种处理异步操作结果的方式。Promise 的好处在于,它的编码风格更像是同步代码。
许多库(如节点“fs”)为某些操作提供同步和异步样式。在操作不需要很长时间并且不经常使用的情况下 - 如在读取配置文件的情况下 - 同步样式操作将导致代码更易于阅读。