为啥 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。例如setTimeout
、setInterval
、I/O 操作、承诺(和async/await
)。
【讨论】:
以上是关于为啥 Javascript 中的函数是同步的?的主要内容,如果未能解决你的问题,请参考以下文章