首页 > 其他分享 >如何减少项目的白屏时间,优化页面的卡顿

如何减少项目的白屏时间,优化页面的卡顿

时间:2023-11-13 19:11:06浏览次数:32  
标签:函数 渲染 batchSize requestAnimationFrame processBatch 白屏 div 卡顿 页面

1.如何减少项目的白屏时间,优化页面的卡顿

问题背景

在某些情况下,我们希望等待当前帧渲染完成后执行某个函数。这样可以确保在进行下一次操作之前,浏览器已经完成了渲染工作,以提供更流畅的用户体验。例如,当我们需要处理大量数据并进行渲染时,我们可以使用 requestAnimationFrame 在下一帧开始时调用处理函数,以避免阻塞主线程。

我们来看下需求,我们需要在页面中渲染多个组件元素,不断插入页面,举例如下:

<!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>
    <div id="main" style="display: flex;flex-wrap: wrap;">
        
    </div>
</body>
<script>
    // 假设有一个包含大量数据的数组
    function processBatch() {
        for (let i = 0; i < 199999; i++) {
            // 渲染数据到页面,例如创建 DOM 元素、更新内容等操作
            const div = document.createElement('div');
            div.style.width=100+'px';
            div.style.height=100+'px';
            div.style.background = 'red';
            div.style.margin='20px';
            document.getElementById('main').appendChild(div);          
    }
    processBatch()
</script>
</html>

我们来看下这个页面的渲染过程以及Performance性能分析

 

我们可以看到在开始的时候会有一段时间的白屏卡顿,如果我们不处理的话,数据量再大,白屏时间会越来越长。

 

可以看到有两帧都有长时间的Loog task 阻塞了主任务,这就是我们需要优化的部分,因为浏览器是多线程的,但是js是单线程的,我们需要拆分长任务,可以使用webwork多线程,可以参考我上篇文章 https://www.cnblogs.com/ximenchuifa/p/17789762.html ,我们接下来主要介绍 requestAnimationFrame 渲染帧,是浏览器用于定时循环操作的一个接口,类似于setTimeout,setInterval,但是它们有着严重的性能问题,requestAnimationFrame是一个专门为实现高性能的帧动画而设计的API。

<!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>
    <div id="main" style="display: flex;flex-wrap: wrap;">
        
    </div>
</body>
<script>
    // 假设有一个包含大量数据的数组
    const data = [/* 大量数据 */];
    for (let index = 0; index < 9999; index++) {
        data.push(index)
    }
    // 每帧处理的数据数量
    const batchSize = 100;
​
    // 当前处理的数据索引
    let currentIndex = 0;
​
    // 处理和渲染一批数据的函数
    function processBatch() {
        for (let i = 0; i < 199999; i++) {
            // 处理当前索引的数据
            const item = data[currentIndex];
            // 渲染数据到页面,例如创建 DOM 元素、更新内容等操作
            const div = document.createElement('div');
            div.style.width=100+'px';
            div.style.height=100+'px';
            div.style.background = 'red';
            div.style.margin='20px';
            document.getElementById('main').appendChild(div);
            // 增加当前索引
            currentIndex++;
​
            // 判断是否还有数据需要处理
             if (currentIndex >= data.length) {
                // 数据处理完成
                return;
             }
        }
​
        // 在下一帧继续处理下一批数据
        requestAnimationFrame(processBatch);
    }
​
    // 开始处理和渲染数据
    requestAnimationFrame(processBatch);
    processBatch()
</script>
</html>

 

再看下性能分析

 

再看下发现没有卡顿,很流畅,体验也很丝滑,性能分析也没有警告和Look task了,但是有可能总的渲染时间比起前多。在改进的代码中我们可以看到有个每帧处理的数据数量batchSize,如何确定这个值呢?

确定合适的 batchSize 大小以平衡处理时间和渲染性能是一个挑战,因为它取决于多个因素,包括数据量的大小、处理逻辑的复杂度、设备性能等。下面是一些方法和建议来帮助确定合适的 batchSize 大小:

  1. 设备性能考量:不同设备的性能不同,因此 batchSize 的大小可能需要根据目标设备进行调整。较低性能的设备可能需要较小的 batchSize,以避免过多的计算和渲染压力。

  2. 实时性需求:如果你需要实时性的渲染效果,较小的 batchSize 可能更合适。这样可以更频繁地在每一帧中进行渲染,提供更实时的更新效果。

  3. 用户体验:根据用户的反馈和感知,调整 batchSize 的大小。如果用户觉得页面渲染速度不够流畅,可以尝试减小 batchSize,反之亦然。

  4. 性能监测和优化:使用浏览器的开发者工具进行性能监测,观察每帧的处理时间和页面渲染性能。通过不同的 batchSize 大小进行测试,并分析性能指标,找到一个平衡点。

  5. 增量调整:从一个较小的 batchSize 开始,逐渐增加 batchSize 的大小,同时观察性能和用户体验的变化。一旦达到性能和用户体验的平衡点,就可以确定合适的 batchSize 大小。

请注意,batchSize 的最佳值可能因不同的应用场景和具体需求而有所不同。因此,根据实际情况进行试验、优化和调整是找到最佳 batchSize 大小的关键。

我们可以将其封装成一个通用函数。本文将介绍如何将 requestAnimationFrame 封装成一个通用函数,以便在需要的地方快速调用。

封装通用函数

下面是一个将 requestAnimationFrame 封装成通用函数的示例代码:

function startAnimationFrame(callback) {
  let isRunning = true;
​
  function frame() {
    if (!isRunning) { //取消帧的请求,结束操作
      return;
    }
​
    callback();
    requestAnimationFrame(frame);
  }
​
  requestAnimationFrame(frame);
​
  return function stop() {
    isRunning = false; //在下一次不会继续
  };
}

 

你可以将 processBatch 函数作为参数传递给 startAnimationFrame 函数,它会在每一帧开始时调用 processBatch 函数。该函数还会返回一个 stop 函数,用于停止动画循环。例如:

function processBatch() {
  // 处理和渲染数据的逻辑
}
​
const stopAnimation = startAnimationFrame(processBatch);
​
// 调用 stopAnimation 函数以停止动画循环
// stopAnimation();

 

通过上述代码,我们将 processBatch 函数作为参数传递给 onNextFrame 函数,它将在下一帧开始时调用该函数。这确保了处理函数将在当前帧渲染完成后执行,提供了更好的用户体验。

优势和注意事项

通过封装 requestAnimationFrame 成通用函数,我们可以获得以下优势:

  1. 更好的性能: 在下一帧开始时执行函数可以避免阻塞主线程,提高页面的响应性能。

  2. 更流畅的动画: 在动画场景中,使用 requestAnimationFrame 可以确保每一帧的渲染完成后再进行下一次更新,从而产生更流畅的动画效果。

标签:函数,渲染,batchSize,requestAnimationFrame,processBatch,白屏,div,卡顿,页面
From: https://www.cnblogs.com/ximenchuifa/p/17829893.html

相关文章

  • node+express服务给前端提供markdown数据,前端渲染md文件在页面上
    本文介绍后端怎么把markdown文件发给前端,前端又怎么渲染在页面中。先看效果图md文件代码: 前端网页渲染: 先介绍node+express怎么提供接口:constexpress=require("express");constrouter=express.Router();constfs=require("fs");router.get("/api/getMark......
  • 三年Android开发怒怼某大厂HR,怒刷1549页面试题科大上岸
    最近,有个读者联系了我和我诉说了最近他面试碰到的一件很气愤的事情。为什么方便就称呼小华了。小华目前是三年Android开发,从上个月就开始一直在找工作,因为今年的大环境不好,面试的时候也是处处碰壁,面一家挂一家,面完之后怀疑自我,是不是自己真的太菜了找不到工作。但是也没有气馁多久,......
  • Vue使用vuex刷新页面后state数据丢失
    使用 createPersistedState做持久化安装:npminstallvuex-persistedstate--save使用:importVuefrom'vue';importVuexfrom'vuex';importcreatePersistedStatefrom'vuex-persistedstate'importnavCollapsefrom'./modules/navCol......
  • SharePoint 页面中插入自定义代码
    我们都知道SharePoint是对页面进行编辑的。对于一些有编程基础的人来说,可能需要对页面中插入代码,这样才能更好的对页面进行配置。但是在新版本的SharePointmodern页面来说,虽然我们可以插入Embed组件。但是Embed组件中是不允许提供Script和Html脚本的。只能插入iFrame......
  • SharePoint 页面中插入自定义代码
    我们都知道SharePoint是对页面进行编辑的。对于一些有编程基础的人来说,可能需要对页面中插入代码,这样才能更好的对页面进行配置。但是在新版本的SharePointmodern页面来说,虽然我们可以插入Embed组件。但是Embed组件中是不允许提供Script和Html脚本的。只能插入iF......
  • android 页面切换
    案例演示:首先有MainActivity与LoginActivity两个ActivityMainActivity.javapublicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setConte......
  • CDN 在某些页面上提供图像,但在其他页面上不提供图像
    如果在某些页面上使用CDN提供图像,但在其他页面上不提供图像,可能是以下几个原因导致的:1.页面链接错误:检查在不提供图像的页面上,图像的链接是否正确。确保链接指向CDN上的正确图像位置。2.缓存问题:有可能之前访问缺少图像的页面时,图像链接出现问题,导致浏览器缓存了错误的链接。尝试......
  • 如何避免HTML iframe导致页面刷新
    要避免HTMLiframe导致页面刷新,您可以采取以下几种方法:使用AJAX加载内容:使用JavaScript的AJAX技术来异步加载iframe中的内容,这样就可以避免整个页面的刷新。您可以使用XMLHttpRequest或者jQuery的$.ajax方法来实现异步加载。设置iframe的sandbox属性:将iframe的sandbox属性设置为"al......
  • PHP实现页面间的链接和背景图片设置
    在PHP中实现页面间的链接非常简单,你可以使用HTML的<a>标签来创建链接。下面是一个示例代码,当用户点击按钮后,将跳转到下一个页面:<!--第一个页面--><!DOCTYPEhtml><html><head><title>第一个页面</title></head><body><buttononclick="window.locati......
  • 如何使用透明的div实现页面背景模糊效果
    要在页面背景上实现模糊效果,并使内容区域(<div>)保持半透明,你可以使用CSS的backdrop-filter属性。这个属性可以用于设置页面背景的滤镜效果,而不影响内部内容的模糊。下面是一个示例的代码片段,展示如何实现这个效果:<!DOCTYPEhtml><html><head><title>背景模糊效果</title>......