测试代码
javascript
function btn() {
console.log('test btn');
// btn(); 第一种情况
// setTimeout(btn,0) 第二种情况
// Promise.resolve().then(btn) 第三种情况
}
const normal = document.getElementById("normal")
normal.addEventListener('click', btn)
先有问题再有答案
上面的三种死循环 UI表现如何 会卡死嘛
对js堆栈有哪些影响 无限递归 会报错嘛?
浏览器的一帧如何处理js任务
一帧结合事件循环 会有哪些情况
异步任务会导致栈溢出嘛?
异步任务会导致UI卡死嘛
一帧
浏览器的一帧 关键节点只有两个 主要是执行js和渲染流程,这两个任务。其他浏览器相关api的调用 这里先不讨论。具体可以参考文末的相关文章。
从图中可以看出js中宏任务和微任务会执行几轮 这里具体的执行次数 浏览器会结合当前的运行状态来动态判断。
通常情况下,在一帧的时间内,浏览器会尽可能地执行JavaScript代码,浏览器会在一帧的结束时进行一次页面渲染。因为页面渲染(包括回流&重绘)是一个相对昂贵的操作,频繁地进行页面渲染会消耗大量的CPU和GPU资源,降低页面的性能。
我们需要注意的是执行完宏任务后一定会执行微任务 并且清空当前的微任务队列。然后再来判断是继续执行js还是开启渲染流程。
event-loop
同步stack:
scss
function btn() {
btn();
}
结果: UI卡死 抛出栈溢出异常
此时一帧如图 : 在浏览器抛出栈溢出错误之前,页面会卡死,因为js执行 渲染被阻塞了。
event-loop如图 : 直接调用btn函数会导致同步的无限递归,这个操作会迅速耗尽调用栈空间,在很短的时间内引发"RangeError: Maximum call stack size exceeded"错误。
异步macrosTask setTimeout:
scss
function btn() {
setTimeout(btn,0)
}
结果:UI可正常滚动 不会抛出栈溢出异常
此时一帧如图 : setTimeout 引入了延迟,将下一个btn调用放到事件循环队列中,而不是直接递归调用。这允许浏览器在两次调用之间处理其他事件,包括UI事件,比如滚动和渲染。因此,即使btn函数持续调用,页面也不会立即卡死。
event-loop如图 : 由于setTimeout的异步性质,它不会导致调用栈溢出。每次setTimeout都会在新的调用栈上运行btn,因此不会出现调用栈大小的异常。
异步Microtask promise:
scss
function btn() {
Promise.resolve().then(btn);
}
结果: UI卡死 不会抛出栈溢出异常
此时一帧如图:
脚本通过Promise不断地以递归方式创建微任务,无限递归的生成微任务 微任务队列永远不会为空 js线程会一直执行微任务 浏览器没有机会去执行其他宏任务,如UI渲染或事件监听器的调用, 这会导致UI渲染被阻塞,界面无法响应用户操作,体验到的结果就如同UI卡死一样。
event-loop如图 :
和setTimeout一样,由于Promise的异步特性和微任务的特点,不会导致调用栈溢出。每次Promise解决时,都会开启一个新的任务来运行btn,不会累积调用栈。
总结
js长时间执行会导致页面一帧中的渲染被推迟 页面会卡顿或者卡死...
栈溢出是指函数调用时,因为调用栈(也就是保存函数调用信息的栈结构)所能容纳的激活记录(activation record,每次函数调用的相关信息)数量超出了限制。这种情况通常发生在深度递归或无限递归的同步函数调用中,因为每次函数调用前没有完成上一次调用
,导致调用栈越积越多,最终超出栈的容量限制。
对于异步的宏任务和微任务来说,它们不会直接导致栈溢出,原因如下:
异步宏任务 :JavaScript引擎使用事件循环来管理异步操作,宏任务(js三座大山之异步七实现宏任务的N种方式)在每次事件循环迭代中执行,宏任务之间会有断点,每个宏任务完成后,调用栈都会清空,然后处理下一个宏任务。这意味着即使是连续安排的多个宏任务,也不会导致调用栈累积而溢出。
异步微任务 :微任务(js三座大山之异步六实现微任务的N种方式)在当前宏任务完成后、下一个宏任务开始前执行。虽然微任务是连续执行的,但每个微任务都是独立入栈的;即使它们形成了长队列,每次只处理一个微任务,处理完后就从调用栈中弹出。因此,即使微任务队列很长,每次执行完毕都会清空调用栈,不会累积导致栈溢出
相关文章
js三座大山之异步一单线程,event loop,宏任务&微任务
js三座大山之异步五基于异步的js性能优化
浏览器:帧&渲染流程