全量加载、懒加载、延迟加载、虚拟列表、canvas、异步分片

背景

前端遇到大数据量的场景,为了提高用户的使用体验,我们需要做很多优化手段。

我们可以从以下的防线去优化:

  • 接口层
    • 分段获取
  • 数据层
    • 分段存储
    • 提高索引速度
      • 字典树
    • 提高存取速度
  • 渲染层

本文围绕渲染层的优化来讲解

思维链

1、懒加载

初始化只渲染首屏的数据,当用户滚动时,渲染额外数据。

优点

  • 首屏加载快

缺点

  • 随着用户的持续性滚动,真实dom和内存会越来越多
  • 滚动过快有白屏

2、延迟加载

首屏正常渲染,渲染完后,异步渲染其他部分。

我们往往会使用requestAnimationFrame、requestIdleCallback、setTimeout等

特性 requestAnimationFrame requestIdleCallback setTimeout
优点 • 浏览器优化,每帧执行一次 • 不会造成丢帧 • 节省系统资源,页面不是激活状态时,动画暂停 • 在浏览器空闲时执行 • 不影响用户交互和动画 • 可以设置超时时间 • 使用简单 • 兼容性好 • 可以设置延迟时间
缺点 • 不能设置执行时间间隔 • 动画的开始/取消需要手动控制 • 兼容性不如setTimeout • 兼容性最差 • 执行时机不可控 • 可能永远不会执行 • 精度不高 • 容易造成丢帧 • 嵌套调用可能会导致调用栈溢出

优点

  • 很大程度解决了懒加载的问题

缺点

  • 一开始内存占用就很大

3、虚拟加载

无论用户滚动到哪个位置,都只渲染用户可视区域的内容

优点

  • 真实dom少
  • 内存占用固定且少

缺点

  • 滚动过快有白屏

4、canvas

直接抛弃真实dom的渲染,使用canvas来渲染,渲染性能非常强。

优点

  • 渲染快

缺点

  • 实现异常复杂

5、异步分片

  • 大量真实dom的渲染,可以拆分成多个渲染子任务;
  • 对于canvas的渲染,我们可以拆分成多个珊格,从而拆分成多个渲染子任务;

这些渲染子任务队列如果一次性执行,会导致js单线程的卡顿,所以我们需要控制每一帧里执行的子任务的时间,比如每一帧为16ms,那么我们可以拿其中的10ms来执行子任务,剩下的6ms来响应用户的交互,这样就不会导致js单线程的卡顿。

ts 复制代码
// 模拟一个耗时任务队列
const tasks = new Array(10000).fill(0).map((_, index) => () => {
    // 模拟每个任务的执行
    let result = 0;
    for(let i = 0; i < 10000; i++) {
        result += Math.random();
    }
    console.log(`完成任务 ${index}`);
});

class TimeSliceExecutor {
    constructor(tasks) {
        this.tasks = tasks;
        this.timeLimit = 10; // 每帧分配10ms执行任务
    }

    // 执行任务队列
    execute() {
        if (this.tasks.length === 0) {
            console.log('所有任务执行完成');
            return;
        }

        const startTime = performance.now();
        
        while (this.tasks.length > 0) {
            // 检查是否超过当前帧的时间限制
            if (performance.now() - startTime > this.timeLimit) {
                // 超过时间限制,在下一帧继续执行
                requestAnimationFrame(() => this.execute());
                break;
            }

            // 执行一个任务
            const task = this.tasks.shift();
            task();
        }
    }

    // 开始执行
    start() {
        requestAnimationFrame(() => this.execute());
    }
}

// 使用示例
const executor = new TimeSliceExecutor(tasks);
executor.start();
相关推荐
编码浪子2 小时前
趣味学RUST基础篇(智能指针_结束)
开发语言·算法·rust
爱编程的化学家3 小时前
代码随想录算法训练营第六天 - 哈希表2 || 454.四数相加II / 383.赎金信 / 15.三数之和 / 18.四数之和
数据结构·c++·算法·leetcode·双指针·哈希
BillKu3 小时前
Vue3 + Element-Plus 抽屉关闭按钮居中
前端·javascript·vue.js
面向星辰4 小时前
html中css的四种定位方式
前端·css·html
Async Cipher4 小时前
CSS 权重(优先级规则)
前端·css
大怪v4 小时前
前端佬:机器学习?我也会啊!😎😎😎手“摸”手教你做个”自动驾驶“~
前端·javascript·机器学习
Liquad Li5 小时前
Angular 面试题及详细答案
前端·angular·angular.js
用户21411832636025 小时前
首发!即梦 4.0 接口开发全攻略:AI 辅助零代码实现,开源 + Docker 部署,小白也能上手
前端
闲人编程5 小时前
图像去雾算法:从物理模型到深度学习实现
图像处理·人工智能·python·深度学习·算法·计算机视觉·去雾
咔咔学姐kk5 小时前
大模型微调技术宝典:Transformer架构,从小白到专家
人工智能·深度学习·学习·算法·transformer