用文字记录生活,留下美好瞬间
原创

JavaScript 中分时函数的优势:解决创建大量节点的性能问题

共 3,341 字,需阅读 8 分钟
2018/12/28 上午
272 次阅读

标题:JavaScript 中分时函数的优势:解决创建大量节点的性能问题

在网页开发中,我们经常需要操作 DOM 元素,其中一个常见的任务是动态创建大量节点。但是,如果不加以控制,一次性创建大量节点可能会导致浏览器性能问题,甚至导致页面卡顿或崩溃。在本文中,我们将探讨这个问题,并介绍一种解决方案——分时函数。

#问题引出:一次性创建大量节点可能带来的问题

为了演示问题的严重性,让我们先来实现一个简单的按钮,点击该按钮后会创建 10 万个节点。

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>创建大量节点</title> </head> <body> <button id="createNodesBtn">创建节点</button> <div id="container"></div> <script> const createNodesBtn = document.getElementById('createNodesBtn'); const container = document.getElementById('container'); const datas = new Array(10000).fill(0).map((_, index) => index); createNodesBtn.addEventListener('click', () => { for (const i of datas) { const node = document.createElement('div'); node.innerText = i; container.appendChild(node); } }); </script> </body> </html>

在点击按钮后,浏览器将尝试一次性创建并插入 10 万个 <div> 节点到页面中,会造成主线程阻塞,这将严重影响页面性能。

造成卡顿的原因是什么呢? 我们知道,浏览器的渲染机制是:主线程负责渲染页面,渲染过程中,主线程会阻塞,直到渲染完成。现在,我有一个任务,比较长,导致这个任务没有给浏览器流出任何的空间,所以浏览器的渲染时机被延后了,多出的这段时间就是卡顿。

如何优化呢?

#分时函数的介绍

分时函数是一种用于分割任务执行时间的技术。它将一个耗时较长的任务分成多个小任务,在一段时间内逐步执行,从而减轻了单次任务对浏览器性能的影响。

#说到分时函数这里不得不讲到 requestIdleCallback

requestIdleCallback是浏览器提供的一种API,用于在浏览器空闲时段内执行特定的回调函数。这个API的主要目的是优化网页性能,特别是针对那些需要在主进程空闲时进行的任务,以避免阻塞主线程影响页面渲染和用户交互。

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
window.requestIdleCallback(function callback(deadline) { // deadline 对象包含了两个属性:timeRemaining 和 didTimeout // timeRemaining 返回一个估算值,表示在下一次屏幕刷新之前,回调还可以运行多久 // didTimeout 表示是否因为超时而调用(如果设定了超时时间) while (deadline.timeRemaining() > 0 && tasks.length > 0) { const task = tasks.shift(); task(); } if (tasks.length > 0) { // 如果还有任务没完成,再次请求回调 requestIdleCallback(callback); } }, { timeout: 5000 /* 可选,超时时长 */ });

在上述代码中,requestIdleCallback接受两个参数:

callback:当浏览器进入空闲状态时调用的函数。该函数接收一个deadline对象作为参数,通过它来了解剩余可用时间。

options:可选参数对象,包含一个可选的timeout属性,指定回调函数等待执行的最大时间(毫秒),超过这个时间后无论浏览器是否空闲都会执行回调。

requestIdleCallback非常适合用来处理一些低优先级的工作,比如预加载图片、日志记录、批处理DOM更新等,确保这些任务不会影响到关键的用户体验。但需要注意的是,并非所有浏览器都支持此API,实际开发中可能需要引入polyfill或者采用其他兼容方案。

#分时函数的示例代码

下面是一个使用分时函数的示例代码,用于优化上面的创建节点任务:

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
function chunk(data, taskHandler, scheduler) { if (!data.length) { return } let i = 0; // 开启下一个分片执行 function _run() { if (i >= data.length) { return; } // 一个渲染帧中,空闲时开启分片执行 requestIdleCallback((idle) => { while(idle.timeRemaining() > 0 && i < data.length) { taskHandler(data[i], i); i++; } // 此次分片完成 _run(); } } _run(); } createNodesBtn.addEventListener('click', () => { const datas = new Array(100000).fill(0).map((_, index) => index); const taskHandler = (i) => { const div = document.createElement('div'); div.innerText = i; document.body.appendChild(div); } chunk(datas, taskHandler) });

#分时函数的优势

  1. 减少页面卡顿和崩溃风险: 使用分时函数可以有效减少一次性大量操作对浏览器的负担,从而降低页面卡顿和崩溃的风险。
  2. 提升用户体验: 分时函数可以让页面逐步展现内容,而不是一次性全部呈现,这可以提升用户体验,让用户感觉页面加载更加流畅。
  3. 优化页面性能: 通过分时函数,我们可以更好地利用浏览器资源,合理分配任务执行时间,从而优化页面性能。

总的来说,分时函数是一种非常有效的优化技术,特别是在处理大量节点创建等耗时任务时,它能够帮助我们提升页面性能,改善用户体验。在实际开发中,我们应该根据具体情况合理运用分时函数,以达到更好的效果。

自由转载 - 署名 - 非商业性使用
https://zhangwurui.cn/article/36
0/0条看法
访客身份
在下有一拙见,不知...
期待你的捷足先登