为啥 Javascript 中的函数是同步的?

Posted

技术标签:

【中文标题】为啥 Javascript 中的函数是同步的?【英文标题】:Why are functions synchronous in Javascript?为什么 Javascript 中的函数是同步的? 【发布时间】:2020-01-10 18:00:42 【问题描述】:
console.log("start")
myfunc()
console.log("end")

function myfunc()
  for(i=0; i<100000000; i++)

  
  console.log("this should be the end")

代码的输出总是:

start
this should be the end
end

是否应该 myfunc() 在节点中执行并花费更长的时间,以便由于 javascript 是异步的,所以应该更早地调用“end”?

【问题讨论】:

不,为什么要这样? JavaScript 是同步的。 JavaScript 不是异步的,你从哪里得到的信息? @David 你在这里是一个同步的 for 循环,意思是 myfunc() 将在循环完成后返回。为此,您需要明确使用 Promises/async/await(即在异步函数中运行循环) Javascript code 总是同步的。但是网络和磁盘 I/O 等一些低级功能是异步的,以避免阻塞其他代码。 Javascript 在这方面并不特殊,它与 C、C++、Java、Python 等完全一样。唯一的例外是 javascript 要么没有同步 I/O,要么强烈反对同步 I/O @David 好吧,就 I/O 操作而言,JavaScript 和 Python 完全不同 【参考方案1】:

Javascript 具有异步操作。但是,for 循环是同步的,而不是异步的。您展示的代码没有使用任何异步操作,因此都是同步的。

myfunc() 是否应该在节点中执行并花费更长的时间,以便由于 javascript 是异步的,所以应该更早地调用“end”?

没有。 myfunc() 中没有任何内容是异步的。这就是您问题中的所有同步代码。

setTimeout()http.get()fs.readFile()等操作都是异步操作。它们不会改变 for 循环同步运行的事实,但是对您可能放入循环中的任何异步的响应将在您的 console.log("end") 运行之后发生。

如果你做了这样的事情:

console.log("start")
myfunc()
console.log("end")

function myfunc()
  for(let i=0; i<10; i++)
      setTimeout(function() 
          console.log(`timer $i done now`);
      , 100);
  
  console.log("this should be the end")

然后会显示这个输出:

start
this should be the end
end
timer 0 done now
timer 1 done now
timer 2 done now
....

这是操作顺序:

    输出console.log("start") 调用 myfunc() 从 10 个 setTimeout() 异步操作开始运行 for 循环 完成for循环并输出console.log("this should be the end") myfunc()返回 输出console.log("end") 一段时间后,第一个计时器完成并调用其回调并输出timer 0 done now。 其余计时器结束 for 循环同步运行并启动所有计时器,然后myfunc() 返回。

【讨论】:

如果将 HTTP 请求放入该函数会怎样? HTTP 请求将是异步的,但 for 循环仍将是同步的 - 它会调度(不执行)HTTP 请求,直到所有 javascript 执行结束(到达脚本)然后解释器会注意到没有其他要执行的东西并会发出 HTTP 请求 @David - 我在答案中添加了一个示例。【参考方案2】:

正如jfriend 所说,您的代码是完全同步的。这是发生的事情(非常非常粗略):

console.log('start') 被添加到调用堆栈中——它触发然后退出调用堆栈,您会看到提供的消息 myFunc 被添加到调用栈中(注意 JavaScript 是 LIFO,或者last in, first out) 在myFunc 执行上下文中,您有一个循环的for 循环——即使它没有显式地做任何事情,它也隐含地做了很多事情,包括变量赋值、比较和递增——所有这些都一个接一个地发生(同步行为) 循环完成后,console.log('this should be the end') 被添加到调用堆栈(仍在myFunc 执行上下文中),并记录到控制台,然后退出调用堆栈 接下来,myFunc 退出调用堆栈 最后,console.log('end') 进入调用堆栈,触发,然后退出调用堆栈

如果您想查看实际的异步行为,可以使用 API。例如setTimeoutsetInterval、I/O 操作、承诺(和async/await)。

【讨论】:

以上是关于为啥 Javascript 中的函数是同步的?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我应该在javascript中的每个函数后使用分号?

为啥函数的参数对象不是 Javascript 中的数组?

为啥正文中的 javascript 函数优先于头部中的函数?

如何在同步函数中等待 JavaScript 中的异步调用?

javaScript中的同步,异步与回调函数

为啥我应该将函数分配给 javascript 中的变量? [复制]