js函数调用面试题

78 阅读1分钟

1、报错:超出最大调用堆栈大小

function foo() {
    foo()
}
foo()

image.png

2、正常执行:堆栈不会溢出

function foo() {
    setTimeout(foo,0)
}
foo()

步骤

image.png

  1. 调用 foo()会将foo函数放入调用堆栈(call stack)。
  2. 在处理内部代码时,JS引擎遇到setTimeout
  3. 然后将foo回调函数传递给WebAPIs(箭头1)并从函数返回,调用堆栈再次为空
  4. 计时器被设置为0,因此foo将被发送到任务队列(箭头2)。
  5. 由于调用堆栈是空的,事件循环将选择foo回调并将其推入调用堆栈进行处理。
  6. 进程再次重复,堆栈不会溢出。

运行示意图如下所示: image.png

3、浏览器无法响应

function foo() {
    return Promise.resolve().then(foo);
}
foo()

JavaScript中有宏任务和微任务。setTimeout回调是宏任务,而Promise回调是微任务。

主要的区别在于他们的执行方式。宏任务在单个循环周期中一次一个地推入堆栈,但是微任务队列总是在执行后返回到事件循环之前清空。因此,如果你以处理条目的速度向这个队列添加条目,那么你就永远在处理微任务。只有当微任务队列为空时,事件循环才会重新渲染页面

每次调用’foo‘都会继续在微任务队列上添加另一个’foo‘回调,因此事件循环无法继续处理其他事件(滚动,单击等),直到该队列完全清空为止。 因此,它会阻止渲染。

来源链接:blog.sciencenet.cn/home.php?mo…