当我们在页面执行渲染时候,如果这个渲染次数达到百万级别时候,界面会瞬间卡死不动
for (let i = 0; i < 10000; i++) {
for (let j = 0 ; j < 10000; j++) {
// console.log(i + ' ' + j)
document.getElementById('task').innerText = i + '-' + j
}
}
优化点
- 可以延迟渲染执行(不是利用简单的setTime)
- 利用浏览器空闲事件去处理渲染数据
- 增加第一层循环次数,减少第二层循环尺寸,每次执行第一层循环次数,走延迟渲染
具体代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="invokebtn">执行耗时任务</button>
<span id="time"></span>
<span id="task"></span>
<script>
function _runTask2(task, callback) {
// 兼容性不好,safari不兼容
requestIdleCallback((idle) => {
// 判断主线程执行完,是否还有剩余时间
if (idle.timeRemaining() > 0) {
task();
callback();
} else {
_runTask(task, callback)
}
})
}
function _runTask(task, callback) {
// 自己实现是否有空余时间
let start = Date.now()
requestAnimationFrame((idle) => {
// 判断主线程执行完,是否还有剩余时间
let diff = Date.now() - start
// console.log(diff)
if ( diff < 16.6) {
task();
callback();
} else {
_runTask(task, callback)
}
})
}
// 执行一个任务,要求异步执行任务,返回Promise
// 要尽快完成任务,同时不能让页面卡顿
// 尽量兼容更多浏览器
function runTask(task) {
return new Promise((resolve) => {
// 1放入微队列, 还是会堵塞
// Promise.resolve().then(() => {
// task()
// resolve()
// })
// 2宏任务队列
// 取出宏队列第一个任务
// 执行任务
// 判断是否达到渲染时间,达到了,渲染
// setTimeout(() => {
// task()
// resolve
// }, 0)
_runTask(task, resolve)
})
}
document.getElementById('invokebtn').addEventListener('click' , function () {
for (let i = 0; i < 100000; i++) {
runTask(() => {
for (let j = 0 ; j < 500; j++) {
// console.log(i + ' ' + j)
document.getElementById('task').innerText = i + '-' + j
}
})
}
})
let i = 0 ;
setInterval(() => {
document.getElementById('time').innerText = i++
}, 10)
</script>
</body>
</html>