直奔主题,如果页面中有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代码:- 监听主线程发送的消息,当收到类型为
start
的消息时,开始处理任务。- 定义一个calculateSum
函数,使用reduce
方法计算数组中所有数字的和。- 将计算结果通过postMessage
发送回主线程。
运行步骤
- 将主线程代码保存为
index.html
文件。 - 将Web Worker代码保存为
worker.js
文件,并确保与index.html
文件在同一目录下。 - 在浏览器中打开
index.html
文件,查看控制台输出的结果。
通过这种方式,我们可以利用Web Worker在后台线程中处理耗时的任务,避免阻塞主线程,提高页面的响应性能。
其他方案就不一一举例了,有兴趣的可以自己了解一下!
版权归原作者 一只理智恩 所有, 如有侵权,请联系我们删除。