lgwebdream / FE-Interview

🔥🔥🔥 前端面试,独有前端面试题详解,前端面试刷题必备,1000+前端面试真题,Html、Css、JavaScript、Vue、React、Node、TypeScript、Webpack、算法、网络与安全、浏览器

Home Page:https://lgwebdream.github.io/FE-Interview/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Day218:说下下面两段代码执行情况

Genzhen opened this issue · comments

// 代码片段一:是否存在堆栈溢出错误?
function foo() {
  setTimeout(foo, 0);
}
foo();

// 代码片段二:如果在控制台中运行以下函数,页面(选项卡)的 UI 是否仍然响应?
function foo() {
  return Promise.resolve().then(foo);
}

每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案
欢迎大家在下方发表自己的优质见解
二维码加载失败可点击 小程序二维码

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。

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

因为不是循环是添加到栈,而是执行foo添加到调用栈,执行set添加到宏任务,等待foo内代码执行完,走宏任务,在此执行foo。
2. 会
大多数时候,开发人员假设在事件循环图中只有一个任务队列。但事实并非如此,我们可以有多个任务队列。由浏览器选择其中的一个队列并在该队列中处理回调。
在底层来看,JavaScript中有宏任务和微任务。setTimeout回调是宏任务,而Promise回调是微任务。
主要的区别在于他们的执行方式。宏任务在单个循环周期中一次一个地推入堆栈,但是微任务队列总是在执行后返回到事件循环之前清空。因此,如果你以处理条目的速度向这个队列添加条目,那么你就永远在处理微任务。只有当微任务队列为空时,事件循环才会重新渲染页面