JS 执行 100 万个函数
web workers
可以考虑使用web workers来将这些任务从主线程中分离出来
webworkers允许在后台线程中运行脚本,从而避免阻塞主线程,保持页面的响应性
js
// 主线程
const worker=new Worker('worker.js');//创建新的web worker
worker.postMessage({start:0, end: 1000000});
worker.onmessage=function(event){
const result=event.data;
console.log('任务完成',result);
};
// worker.js代码
onmessage=function(event){
const start=event.data.start;
const end=event.data.end;
let sum=0
for(let i=start;i<=end;i++){
sum+=i;
}
postMessage(sum);//像主线程发送消息
}
requestAnimationFrame实现任务调度
本质是利用requestAnimationFrame对大批量的执行任务进行分割
,requestAnimationFrame的调用频率通常与显示器的刷新率相匹配(60Hz,每秒60次),这样可以确保动画在不同设备上都能保持流畅
js
// 假设有一个包含大量元素的数组
const bigArray = Array.from({ length: 1000000 }, (_, i) => i + 1);
// 定义一个处理函数,例如对数组中的每个元素进行平方操作
function processChunk(chunk) {
return chunk.map(num => num * num);
}
// 分割任务并使用requestAnimationFrame
const chunkSize = 1000; // 每个小块的大小
let index = 0;
function processArrayWithRAF() {
function processChunkWithRAF() {
const chunk = bigArray.slice(index, index + chunkSize); // 从大数组中取出一个小块
const result = processChunk(chunk); // 处理小块任务
console.log('处理完成:', result);
index += chunkSize;
if (index < bigArray.length) {
requestAnimationFrame(processChunkWithRAF); // 继续处理下一个小块
}
}
requestAnimationFrame(processChunkWithRAF); // 开始处理大数组
}
processArrayWithRAF();
动态调整 chunkSize 的大小
js
const $result = document.getElementById("result");
// 假设有一个包含大量元素的数组
const bigArray = Array.from({ length: 1000000 }, (_, i) => i + 1);
// 定义一个处理函数,对数组中的每个元素执行一次
function processChunk(chunk) {
return `chunk: ${chunk}`;
}
// 动态调整 chunkSize 的优化方式
let chunkSize = 1000; // 初始的 chunkSize
let index = 0;
function processArrayWithDynamicChunkSize() {
function processChunkWithRAF() {
let startTime = performance.now(); // 记录结束时间
for (let i = 0; i < chunkSize; i++) {
if (index < bigArray.length) {
const result = processChunk(bigArray[index]); // 对每个元素执行处理函数
$result.innerText = result;
index++;
}
}
let endTime = performance.now();
let timeTaken = endTime - startTime; // 计算处理时间
// 根据处理时间动态调整 chunkSize
if (timeTaken > 16) { // 如果处理时间超过一帧的时间(16毫秒),则减小 chunkSize
chunkSize = Math.floor(chunkSize * 0.9); // 减小10%
} else if (timeTaken < 16) { // 如果处理时间远小于一帧的时间(8毫秒),则增加 chunkSize
chunkSize = Math.floor(chunkSize * 1.1); // 增加10%
}
if (index < bigArray.length) {
requestAnimationFrame(processChunkWithRAF); // 继续处理下一个小块
}
}
requestAnimationFrame(processChunkWithRAF); // 开始处理大数组
}
processArrayWithDynamicChunkSize();
requestIdleCallback
window.requestIdleCallback是一个用于在浏览器空闲时执行任务的API,允许开发者在浏览器的主线程空闲时执行一些任务
,而不会影响用户界面的流畅性和响应性
requestIdleCallback接受一个回调函数作为参数,该回调函数会在浏览器空闲时被调用
js
window.requestIdleCallback(function(deadline) {
// 在空闲时执行的任务
// deadline 参数提供了一些信息,比如剩余的空闲时间等
});
还有一个配套的 window.cancelIdleCallback 方法,用于取消通过 requestIdleCallback 请求的回调
js
const id = window.requestIdleCallback(function(deadline) {
// 在空闲时执行的任务
});
// 取消回调
window.cancelIdleCallback(id);
requestIdleCallback 并不是所有浏览器都支持的标准,因此在使用时要注意检查浏览器的兼容性。
参考
https://github.com/pro-collection/interview-question/issues/672