“发得快“踩坑笔记-为什么过渡动画卡顿了?

过渡动画卡顿的解决方案

遇到这个问题的过程

发得快项目在优化时,有个优化是在切换菜单时,让菜单有一个过渡动画,但是在切换到订单时,过渡动画有一个明显的卡顿,要做的就是解决这个卡顿。

代码如下:(代码为demo,公司代码不可泄露)


<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Documenttitle>
        <style>
            #menu {
      
                width: 100px;
                height: 100px;
                background: #000;
                transition: all 2s;
                color: #fff;
            }
            #menu.selected {
      
                background: #f00;
            }
        style>
    head>
    <body>
        <div id="menu">点击触发过渡动画div>
        <script>
            let menu = document.getElementById("menu");
            menu.onclick = function () {
      
                // 计时器模拟异步http请求订单
                setTimeout(() => {
      
                    kill();
                }, 500);
                // 切换选中状态
                if (menu.classList.value.includes("selected")) {
      
                    menu.classList.remove("selected");
                } else {
      
                    menu.classList.add("selected");
                }
            };

            // while循环卡住js两秒,模拟订单渲染阻塞
            function kill() {
      
                var start = +new Date();
                while (+new Date() - start < 2000) {
      }
            }
        script>
    body>
html>

分析问题原因

首先分析卡顿原因,订单界面数据量较大,渲染这个页面需要较长的时间,js执行进程去渲染订单表格时间过长,打断了过度动画的计算,所以出现了卡顿的情况。

浏览器进程与线程分析

浏览器分为几个进程

  • 主进程
  • 插件进程
  • GPU进程
  • 渲染进程(一个tab页一个进程)

渲染进程又分为几个线程

  • GUI线程
  • js执行线程
  • dom事件线程
  • 计时器线程
  • http线程

关于这个案例,我们需要用到GPU进程,GUI线程与js执行线程

js执行线程主要负责执行js代码,计算HTML 元素的 CSS 样式,绘制位图
GUI线程负责将js绘制好的位图递交给GPU进程,然后GPU进程渲染页面

angular框架在拿到定单数据后做了什么?

拿到定单数据以后,将定单数据赋值给表格的data,angular框架的diff算法计算出改变的虚拟dom节点,并开始绘制,但是50条数据过于庞大,绘制时间过久,造成了卡顿

如何解决

知道了问题是如何发生的,那么就可以思考解决方式,我目前找到了两种方式可以解决这个问题

分散渲染时间

浏览器渲染50条数据时间太久,那么我们就不要一次渲染那么多,只渲染当前能看到的就可以,其他的以后再说,那么渲染的少了,卡顿时间自然也就少了

这种方法没有降低总的渲染时间,只是将一大块时间分散开了,那么在每段时间的间隔中,就可以继续执行过渡动画的渲染

这种思路对应的解决方法是ng-zorro的虚拟滚动,类似懒加载

ng-zorro虚拟滚动示例

使用特定的css

在上网查资料的时候,发现了一个很有意思的demo
demo链接

同样是js阻塞,凭什么transform可以继续动,定位就卡住了呢?
带着这个问题,去查阅资料
发现浏览器对一些css样式有优化处理

深入浏览器理解CSS animations 和 transitions的性能问题
↑这个文章的图片丢失了
图片可以参考这个文章的图片↓
CSS3 动画卡顿解决方案

所以是浏览器对transform,opacity,filter属性有优化
猜测: 浏览器会优化这几个样式是因为,甭管这几个样式怎么变化,都不会影响到其他的dom元素,所以这部分的位图只需要计算一遍就完事了,没有必要重复递交

那么根据这个思路我们改进代码


<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Documenttitle>
        <style>
            #menu {
      
                width: 100px;
                height: 100px;
                background: #000;
                color: #f00;
                transition: all 2s linear;
                opacity: 0.2;
            }
            #menu.selected {
      
                opacity: 1;
            }
        style>
    head>
    <body>
        <div id="menu">点击开始过渡动画div>
        <script>
            let menu = document.getElementById("menu");
            menu.onclick = function () {
      
                setTimeout(() => {
      
                    kill();
                }, 500);
                if (menu.classList.value.includes("selected")) {
      
                    menu.classList.remove("selected");
                } else {
      
                    menu.classList.add("selected");
                }
            };
            function kill() {
      
                var start = +new Date();
                while (+new Date() - start < 2000) {
      }
            }
        script>
    body>
html>

这样,通过opacity属性,我们也解决了这个卡顿问题

但是这两个方法都有缺点

懒加载方法如果加载的部分需要的时间也比较久的话(比如遇到垃圾电脑),那也会造成卡顿
而更改css属性的方法,由于只有这么几个属性有优化效果,所以并不是所有的动画效果都可以做到的,而且这个方法只解决了卡顿,订单表格加载慢的问题依然存在

所以以后遇到这种过渡动画卡顿的情况,最好把两个方法结合起来

查资料三天,写博客两小时,点个赞噻?

你可能感兴趣的:(前端优化,css)