直奔主题,如果页面中有100万个任务需要执行,怎么保证页面不卡顿?
可以采取以下几种策略:
-  任务分片执行: - 利用requestIdleCallback和requestAnimationFrame来分片执行任务。requestIdleCallback可以在浏览器空闲时执行任务,而requestAnimationFrame则可以在每次重绘前执行一个任务,这样可以保证在不影响页面渲染的情况下执行任务。
 
- 利用
-  Web Worker多线程处理: - 使用Web Worker可以在独立线程中执行JavaScript代码,避免主线程阻塞,从而提高页面响应速度。
 
-  懒加载技术(Lazy Loading): - 对于不需要立即执行的任务,可以采用懒加载技术,即在需要时才加载和执行,减少初始加载的压力。
 
-  优化DOM操作: - 减少DOM操作和重绘重排,例如通过缓存DOM属性值来减少回流和重绘。
 
-  简化DOM结构: - 简化DOM结构可以减少渲染和操作的复杂度,提高性能。
 
-  函数式组件和变量本地化: - 在Vue中,使用函数式组件可以减少渲染开销,同时将多次引用的变量保存起来,减少响应式对象的getter触发次数,提高性能。
 
-  子组件分割: - 将耗时任务分割到子组件中,利用Vue的组件粒度更新机制,避免不必要的渲染和计算。
 
-  第三方插件按需引入: - 按需引入第三方组件库,避免体积过大,减少不必要的加载和执行。
 
-  路由懒加载: - 在单页应用中,使用路由懒加载可以减少首页加载时需要加载的内容,加快加载速度。
 
-  监控和定位卡顿: - 使用Performance工具监控页面性能,定位耗时任务,并进行优化。
 
方案1:任务分片通常是指将一个大任务分解成多个小任务,并在浏览器的空闲时间里逐一执行这些小任务,以此来避免长时间的阻塞主线程。下面是一个使用requestIdleCallback实现任务分片的示例代码。这个例子中,我们将模拟一个需要处理100万个数字并将它们相加的任务。 
 
// 模拟一个包含100万个数字的数组
const numbers = new Array(1000000).fill(1).map((x, i) => i + 1);// 用于累加的变量
let sum = 0;// 任务分片执行的函数
function processNumbers(start, end, deadline) {// 检查是否还有剩余任务if (start < end) {// 计算当前空闲时间可以处理的任务数量const chunk = Math.min((end - start) / 2, 10000); // 每次处理10000个数字for (let i = start; i < start + chunk; i++) {sum += numbers[i];}// 递归调用,处理下一批任务requestIdleCallback((deadline) => {processNumbers(start + chunk, Math.min(start + chunk * 2, end), deadline);});}
}// 开始执行任务分片
requestIdleCallback((deadline) => {processNumbers(0, numbers.length, deadline);
});window.addEventListener('load', () => {console.log(`The sum of numbers is: ${sum}`);
});这段代码首先创建了一个包含100万个数字的数组,然后定义了一个processNumbers函数,该函数接受三个参数:起始索引start、结束索引end和deadline对象。deadline对象包含了timeRemaining()方法,该方法返回浏览器在当前帧剩余的时间,单位为毫秒。
在processNumbers函数中,计算出当前空闲时间可以处理的任务数量,并在数组的指定范围内进行累加操作。然后,我们递归地调用requestIdleCallback来处理下一批任务,直到所有任务都被处理完毕。
最后,在页面加载完成后在控制台输出累加的结果。
注意,这个代码只是一个示例,实际应用中可能需要根据具体任务进行调整。此外,由于requestIdleCallback是异步的,所以最终的累加结果sum可能不会立即可用,需要在所有任务完成后才能获取。
方案2:使用Web Worker可以实现多线程处理任务,这样可以避免主线程阻塞。下面是一个使用Web Worker处理100万个数字求和的示例代码。
主线程代码(HTML文件)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>const worker = new Worker("worker.js");//监听worker消息worker.onmessage = function (e) {console.log(e.data);};//启动worker任务worker.postMessage({type: "start",numbers: new Array(1000000).fill(1).map((x, i) => i + 1),});</script></body>
</html>
Web Worker代码(worker.js)
//接收主线程消息
self.onmessage = function (e) {if (e.data.type === "start") {const numbers = e.data.numbers;const sum = calculateSum(numbers);postMessage(sum);}
};
//计算数组中所有数字的和
function calculateSum(numbers) {return numbers.reduce((acc, curr) => acc + curr, 0);
}
说明
-  主线程代码: - 创建一个Web Worker实例,指向worker.js文件。
- 监听Web Worker的消息,当收到消息时,在控制台输出结果。
- 向Web Worker发送一个包含100万个数字的数组,并启动求和任务。
 
- 创建一个Web Worker实例,指向
-  Web Worker代码: - 监听主线程发送的消息,当收到类型为start的消息时,开始处理任务。
- 定义一个calculateSum函数,使用reduce方法计算数组中所有数字的和。
- 将计算结果通过postMessage发送回主线程。
 
- 监听主线程发送的消息,当收到类型为
运行步骤
- 将主线程代码保存为index.html文件。
- 将Web Worker代码保存为worker.js文件,并确保与index.html文件在同一目录下。
- 在浏览器中打开index.html文件,查看控制台输出的结果。
通过这种方式,我们可以利用Web Worker在后台线程中处理耗时的任务,避免阻塞主线程,提高页面的响应性能。
其他方案就不一一举例了,有兴趣的可以自己了解一下!