• 关于页面渲染的一些优化方案分享(懒加载、虚拟列表)


    关于页面渲染的一些优化方案分享(懒加载、虚拟列表)

    《工欲善其事,必先利其器》

    banner
    (图片取自百度,侵删。)

    关于前端性能优化,是我们老生常谈的一个知识点了。性能优化的概念非常多,诸如 FP(First Paint)FCP(First Contentful Paint)LCP(Largest Contentful Paint)TTI(Time To Interactive)TBT(Total Blocking Time) 等等。

    但仅仅了解概念是不够的,实际工作上需要如何落地这些优化方案,对我们开发还是有着一定的难度,这也是前端进阶之路上必然需要经历的。否则你将永远无法晋升为中级/高级前端工程师。接下来我会就其中几点,发表一些自己的看法和优化方案。

    我自认为我还是不成熟的,如果文中有地方描述的不正确的地方,我愿意接受大家的指正,也非常欢迎大家一起共同探讨更优的方案!

    一、首屏渲染

    首屏渲染 优化常用的手段是使用加载画面,待首屏加载完成之后,取消加载画面。这个功能的实现我们可以通过 Performance API 来获取其加载的时间,从而控制加载画面的显隐。

    虽然它有存在的必要,但却并不是长久之计,当首页的网络请求很多时,为了用户的体验着想,我们可不能让用户的界面一直停在那里转圈圈哦。

    当首页需要加载多个网络请求

    采用分片请求加载数据

    何为分片请求?例如首页总共有10个网络请求,我们没有必要等待10个网络请求全部加载完之后,再取消加载画面。

    相反的,我们可以优先加载2个比较重要的网络请求,利用这2个网络请求,来控制加载画面。也就是说,相比于上面加载全部的网络请求,我只需要加载2个,这两个网络请求加载完成之后,取消加载画面,执行回调函数,继续请求其他网络请求。

    采用可视区域加载数据

    实际上,这个知识点是懒加载。利用这一点,我们可以实现:组件懒加载和内容的懒加载。

    而关于如何实现懒加载,网络上也是五花八门。我这里总结了几个比较靠谱的实现方式,大家可以一起来看一看:

    • el.offsetTop - document.documentElement.scrollTop - T <= el.clientHeight。其中,变量 T 是前置高度,即如果你不想让视图滚动到区域顶部加载,而是提前多少像素高度加载;
    • el.getBoundingClientRect() 可以获取这个元素的长宽距离顶部等参数,计算的方式与上一条是相同的;
    • new IntersectionObserver() 交叉观察对象 API。如果两个对象交叉重叠了,就会执行回调函数。这种方式的好处就是可以不用监听滚动和元素对象,缺点是需要调整浏览器的兼容性。

    浏览器兼容性

    • 使用 vue-lazyload 插件。这款插件帮我们做了兼容,可以选择是否使用 IntersectionObserver。vue3 版本使用 vue-lazyload-next
    • 使用 vueuse 插件库。同 IntersectionObserver 一样,vueuse 也封装了这个 API,我们可以直接只用 useIntersectionobserver 实现可视区域交叉的判断。
    采用划分布局权重优化

    或许你听说过 “圣杯布局” ?还是听说过 “双飞翼布局” ?如果听说过那么使用它的意义又是什么?

    圣杯布局和双飞翼布局

    由于 JavaScript 是单线程自上往下执行的,那么考虑到数据太多的情况下,加载的顺序会受到影响,我们需要先让 js 引擎加载重要的内容,因此就产生了圣杯布局和双飞翼布局。

    如上图,我们实现布局权重时,需要把中间栏的代码块,放在左右部分的代码块之前,就能稍微提升用户的使用体验。

    采用 script 标签的 async、defer 属性

    所有 script 标签会严格按照他们在网页中出现的次序被解析。而使用 defer 属性可以把脚本推迟到文档渲染完毕之后再执行,相反 async 属性则是异步加载,两者作用不同。但对于单页面应用用处不大,因为单页面应用一般是通过 script 标签引入 JavaScript 来渲染 DOM 的。

    二、列表渲染

    列表渲染常用的优化方式是分片渲染,也就是分页。

    属于数量不定的叠加网络请求

    DOM 结构简单,数据量不多,采用分片渲染+图片懒加载+骨架屏

    骨架屏

    就像掘金网站采用的优化方案,分片渲染+图片懒加载+骨架屏。图片懒加载的作用是列表翻页之后,图片加载过慢时代替的方案;而骨架屏:一是为了用户进入网站时加载过慢的首屏优化(其实就是加载动画);二是防止用户滚动速度过快而产生的空白断层,从而提升用户体验。

    DOM 结构复杂,数据量极多,采用虚拟列表+骨架屏或模拟滚动条

    注意,懒加载和虚拟列表是不同的概念和方案,不能混为一谈。前者更多的是防止由网络不稳定情况导致的用户体验问题,而后者更多的是防止 DOM 渲染过度的性能问题导致用户的体验问题,两者的侧重点不同。

    虚拟列表
    (图片取自百度,侵删。)

    在实际的工作中,列表项必然不会仅仅只由一个 li 标签组成,必然是由复杂 DOM 节点组成的。那么可以想象的是,当列表项数过多并且列表项结构复杂的时候,同时渲染时,会在 Recalculate Style 和 Layout 阶段消耗大量的时间。

    而虚拟列表就是解决这种问题的一种方案,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。

    如上图,假设有1万条记录需要同时渲染,我们屏幕的可见区域的高度为500px,而列表项的高度为50px,则此时我们在屏幕中最多只能看到10个列表项,那么在首次渲染的时候,我们只需加载10条即可。

    考虑到成千上万条复杂的 DOM 节点形成的列表,必然会导致浏览器的重绘,消耗的性能无法估量。因此,当滚动发生时,虚拟列表将动态的通过计算获得可视区域内的列表项,并将非可视区域内存在的列表项删除。

    骨架屏也是为了防止用户滚动过快而导致的页面空白断层,而防止这一种现象的产生可以使用模拟滚动条,控制用户的滚动速度,来间接的提升用户的体验。

    三、图片渲染

    属于网页的重要元素之一

    采用图片懒加载

    图片懒加载

    如上图,当网页中图片加载过慢时,我们可以使用一张前置静默图片来代替图片的加载的空白期,从而提升用户体验(其实也就是我们上面提到的可视区域加载)。可以是网站的标志性图片,也可以是标志性动图,大部分是使用 loading 动画。

    当然,当图片加载失败时,我们也可以使用 其他图片代替,这也能稍微提升用户体验。

    四、总结

    用户体验要考虑的地方实在是太多啦,目前我学习到的仅仅是以上一些比较常用的知识点,后续会继续学习,继续分享,本篇文章到此就完结了,非常感谢你的阅读!

    希望你的未来一片光明。

  • 相关阅读:
    解决 VMware Network Adapter VMnet1 IP 地址冲突导致无法打开路由器管理页面
    电脑黑屏按什么键恢复?只需要3个键就可以解决黑屏
    表单提交是
    特种品种权限开通和豁免
    java for循环内执行多线程
    redis 源码分析:Jedis 哨兵模式连接原理
    关于知识图谱(第二天)
    [信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取
    GraalVM安装
    Pair和Triple的最佳实践
  • 原文地址:https://blog.csdn.net/LizequaNNN/article/details/127420654