js执行阻塞transition过渡效果

2021-11-24  本文已影响0人  阿明先森

前言

最近在做echarts换肤的过程中遇到了切换主题之后,transition过渡产生了延迟,原因是js异步任务阻塞了页面的渲染。

正文

image.png

图上可以看出,切换了主题之后其他部分没有过渡效果的组件颜色已经切换,中间白色的部分是element组件,饿了么自带的过渡效果要等到js任务执行完才会触发页面重绘。


elementui transition

用例

<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <style>
            :root {
                --bg-color: rgb(67, 69, 73);
            }
            :root[theme='light'] {
                --bg-color: rgb(17, 199, 153);
            }
            body {
                width: 1000px;
                margin: 0;
                margin: 0 auto;
                transition: all 0.3s;
                background: var(--bg-color);
                padding: 120px;
            }
        </style>
        <button class="changeStyle">切换样式</button>
        <script>
            document.querySelector('.changeStyle').onclick = async function onclick(e) {
                document.querySelector('html').setAttribute('theme', 'light');
                const time = new Date().getTime();
                while (new Date().getTime() - time < 1500) {}
                console.log('over');
            };
        </script>
    </body>
</html>


解决方法

* {
   transition: background-color 0s !important;
}
setTimeout(() => {}, 1000)

这里试了下延迟0ms不行,按理说settimeout异步宏任务,也不会阻塞页面渲染的啊,具体原因还不清楚。知道的老铁可以介绍下。


更新

之前的分析存在问题,最近阅读了一篇关于浏览器渲染的文章,其实是因为布局树是依赖dom树和cssom树的,只有当js执行完成之后才会构建布局树,页面才会触发重绘。

image.png

第二次更新

<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <style>
            :root {
                --bg-color: rgb(0, 0, 0);
                --box-color: pink;
            }
            :root[theme='light'] {
                --bg-color: rgb(246, 246, 246);
                --box-color: yellow;
            }
            body {
                width: 1000px;
                margin: 0;
                margin: 0 auto;
                transition: all 0.3s;
                background: var(--bg-color);
                padding: 120px;
            }
            .color-box {
                width: 300px;
                height: 300px;
                background: var(--box-color);
            }
        </style>
        <button class="changeStyle">切换样式</button>
        <div class="color-box"></div>
        <script>
            document.querySelector('.changeStyle').onclick = async function onclick(e) {
                const theme = document.querySelector('html').getAttribute('theme');
                document.querySelector('html').setAttribute('theme', theme === 'light' ? '' : 'light');
                setTimeout(() => {
                    const time = new Date().getTime();
                    while (new Date().getTime() - time < 3000) {}
                    console.log('over');
                }, 150);
            };
        </script>
    </body>
</html>

这次加上了settimeout延时150ms执行一个长耗时的任务,transition的过渡时间是300s,可以看到颜色过渡卡在了中间,等耗时任务执行完了才会继续颜色过渡。

所以js确实会阻塞transition过渡效果。

promise微任务

如果把上述的settimeout 换成promise微任务,又会怎么样呢?

new Promise((resolve, reject) => {
              const time = new Date().getTime();
                    while (new Date().getTime() - time < 3000) {}
                    resolve();
                    console.log('over');
});

此时,html元素上的theme属性会在耗时任务3s执行完了,才会被加上去,当然颜色肯定也是在3s之后才会变化。

上一篇 下一篇

猜你喜欢

热点阅读