NodeJS 代码执行因未写入then的异步函数而暂停

neekobn8  于 2023-03-12  发布在  Node.js
关注(0)|答案(3)|浏览(175)

我正在尝试在nodejs中自学异步编程,我编写这个程序是为了更好地理解异步编程。

async function t(){
    
   for(let b = 0 ;b < 9000000000; b++){

   }

   console.log("Hello World 1")
}

t().then(() => {
    console.log("Hello World 2")
})

console.log("Hello World 3")

如果执行此代码块,则日志输出如下

Hello World 1
Hello World 3
Hello World 2

我觉得这很奇怪,因为空循环花费的时间太长,因此输出应该是

Hello World 3
Hello World 1
Hello World 2

既然Hello World 3已经准备好执行,为什么Hello World 3没有先执行?

yyhrrdl8

yyhrrdl81#

您误解了JavaScript中“异步”行为的概念。
JavaScript是一种单线程语言,这意味着在主线程上一次只能执行一个东西。那么,“异步”意味着什么呢?
像HTTP请求这样的操作是异步的,但是JavaScript不能处理它们,我们编写的代码只是启动异步操作;实际的异步操作在客户端JavaScript的情况下由浏览器处理,或者在NodeJS运行时的情况下由后台线程或操作系统本身处理。
简而言之,异步操作在后台(JavaScript区域之外)进行,同时,其他操作可以在主线程上(JavaScript区域内)执行。
当异步操作完成时,JavaScript代码会得到通知,从而执行我们在启动异步操作时提供的回调函数。
在您的例子中,问题在于有一个长时间运行的循环在主线程上执行,因此,在循环执行期间,其他任何东西都不能执行。
以下步骤总结了代码的执行方式:
1.调用函数t并执行其中的代码。这一切都发生在代码的同步执行过程中。结果,长时间运行的循环阻塞了主线程
1.循环结束后,在控制台上记录'Hello World 1'
1.函数t结束;其返回的promise解析为undefined的值,代码同步执行结束后异步调用t().then(...)的回调函数
1.在控制台上记录"Hello World 3"
1.此时代码的同步执行已经结束,现在可以处理排队的任务了,本例中我们只有一个排队的任务,即t().then(...)回调函数的执行。
回调函数异步调用,将"Hello World 2"记录到控制台。
以下关于异步JavaScript主题的指南是了解此主题的好地方:MDN - Asynchronous JavaScript

7gcisfzg

7gcisfzg2#

仅仅在函数前面写async不会使它成为async。async只会使函数返回promise,但promise主体会立即执行。例如:

const pr = () => new Promise((resolve, reject) => {
    return resolve()
 })

pr().then(() => {
    console.log('hello1')
 })
 console.log("Hello World 3")

这里hello 1将再次首先执行。只有异步的函数将稍后运行。例如fs module。它将异步运行不是因为它被 Package 在promise中,而是因为它是以异步方式实现的。它使用libuv,而libuv又使用后台线程池来异步执行它。有几种方法可以使您自己的代码异步运行:

  1. use setTimeout(()=〉{},0)。0毫秒时,您的代码实际上仍将在主线程上运行,但它只会在主同步代码执行后运行。这不是真正的异步(意味着繁重的任务负载仍在主线程上运行)
    1.使用工作线程。你可以在你的代码运行的地方启动新的线程,这样你的主线程就不会被阻塞。
    1.不太推荐,但有趣的方法,我尝试自己当我有同样的问题,你在过去-使用c++ API来建立自己的异步函数与nodegyp。它将使用线程池相同的方式fs或加密模块使用它。你可以阅读更多关于C++附加组件https://nodejs.org/api/addons.html。这是我的repo,我在那里测试构建它https://github.com/Edddo123/Native-Node-addons。让我知道,如果我能帮助你在其他方面
kyxcudwk

kyxcudwk3#

首先,你的代码不是异步的。

1.第一部分t()将被执行,它里面没有异步函数!所以for执行和hello world 1打印。
1.然后promise在异步模式下等待空闲!hello world 3打印。
1.现在是检查是否履行承诺的空闲时间,请运行hello world 2

您可以将代码更改为:

async function t(){
    
   for(let b = 0 ;b < 9000000000; b++){

   }

   console.log("Hello World 1")
}

setTimeout(()=>{
   t().then(() => {
       console.log("Hello World 2")
   });
}, 1);

console.log("Hello World 3")

相关问题