从svelte/transitions转换会大大减慢网站速度

6

我有一个在Svelte上的项目,感觉很好。

但是当我使用我的安卓手机时,我发现点击后有很长的延迟。


根据我所知,Svelte是最快的框架,因为它使用本地JavaScript代码作为输出(没有虚拟DOM),但这里发生的事情超出了世界(难以解释)。

慢了1000000倍?怎么可能


所以我开始调试和研究。

我发现没有转换时一切都正常,速度很快。

但是当开始使用转换时,网站就会变慢。


调试

使用Chrome开发者工具

enter image description here

只添加transition:scale

像这样<div transition:scale>

enter image description here


如您所见,超过80%的速度归因于缩放转换

enter image description here


解决方案

没有transition:scale

enter image description here

❌之前 ✅现在
3.12秒 5微秒

我不会撒谎,但是这比有动画的那个快了1000000倍。

为什么会发生这种情况

我知道解决方法,但我需要一些解释或一种方法来进行动画而不会非常缓慢。

您在顶部看到的图像是通过快速点击按钮(至少20次)得出的结果


1
它可能基于正在进行动画处理的大量HTML。 - Andrew
3
Svelte绝不是最快的框架,只需看一下基准测试即可。此外,Svelte的transition指令使用JavaScript来动画化事物,因此它不能比在JQuery中构建的类似功能更高效,因为它在主线程中运行并消耗大量CPU与布局回流。要拥有高效的过渡效果,您应该使用纯CSS以从GPU加速中受益。 - n--
2
我不确定为什么这个转换会导致性能下降(提供一个复现将有所帮助),但内置的 Svelte 转换不使用 JS 来动画化事物 - 它们使用 JS 构建 CSS 动画,然后将其应用到元素作为常规 CSS 动画(这是在主线程之外完成的)。请参见教程 - Geoff Rich
1
@GeoffRich “不要使用JS来制作动画-它们使用JS构建CSS动画”你在这个声明中自相矛盾,而且该教程无法提供与技术实现相关的答案,你应该查看源代码(https://github.com/sveltejs/svelte/blob/master/src/runtime/transition/index.ts),只需搜索“getComputedStyle”即可查看Svelte执行了多少布局垃圾,并查看零CSS解决方案的[缓动](https://github.com/sveltejs/svelte/blob/master/src/runtime/easing/index.ts)。 - n--
1
@n--:Goeff 的意思是:JS 不用于在循环中设置样式属性,而是生成动画的 CSS 并启动它。因此,这不是 JS 动画。缓动函数用于计算 CSS 动画中的属性值,而不是直接设置属性。 - H.B.
getComputedStyle 通常只用于获取现有/起始值 一次 - H.B.
1个回答

5

这被称为 布局抖动。当您更改或转换导致样式/布局重新计算的CSS属性时,就会发生这种情况。如果将这些类型的更改应用于许多项的列表,则每个项目都会使之前的计算失效,浪费大量的CPU时间(火焰图底部所有非常小的紫色块都暗示了这一点)。

为了避免这种情况,必须将更改/过渡限制为不引起这些更新的内容。关键在于某些属性(如transform)不会影响布局,而是发生在合成器中,这是一种GPU加速操作。

此外,即使合成器过渡也不是“免费的”,因此应避免同时将它们应用于许多单独的项目。


我详细查看了跟踪记录,因为Svelte转换本身已经是纯合成器; 动画的创建似乎会导致样式重新计算和布局:

enter image description here

这可能是因为此代码与style.animation属性交互。

因此,要么不要同时转换多个项目,要么尝试基于类的转换。

性能比较示例:

<script>
    import { scale } from 'svelte/transition';
    
    let count = 1000;
    let svelte;
    let classBased;
</script>

<label>
    Item count
    <input type=number bind:value={count} />
</label>

<label>
    <input type=checkbox bind:checked={svelte}/>
    Svelte transition
</label>

<label>
    <input type=checkbox bind:checked={classBased}/>
    Class transition
</label>

{#each { length: count } as i}
    {#if svelte}
        <h1 transition:scale={{duration: 300}}>Hello</h1>
    {/if}
{/each}

{#each { length: count } as i}
    <h1 class="transition" class:show={classBased}>Hello</h1>
{/each}

<style>
    .transition {
        visibility: hidden;
        transform: scale(0);
        opacity: 0;
        transition: opacity 0.3s, transform 0.3s, visibility 0s 0.3s;
    }
    .transition.show {
        visibility: visible;
        opacity: 1;
        transform: scale(1);
        transition: opacity 0.3s, transform 0.3s;
    }
</style>

REPL


我正在使用Svelte制作一个模拟时钟,并使用svelte/easing(与本主题中使用的svelte/transition相对)。我注意到性能存在显著问题,但我只在每秒钟动画化一个元素(秒针)。有没有可能通过纯CSS和/或JS来提高性能? - Justin
如果你没有使用非常特殊的缓动函数,你可能只需使用普通的CSS动画/过渡。动画一个元素真的不应该成为性能问题。我建议你提出一个单独的问题并展示你的代码,这样人们可以更容易地提供适当的解决方案。 - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接