Svelte tick() 不强制更新变量

Svelte tick() not forcing updates to variables

我已经 运行 解决了 svelte 中看似常见的问题,但还没有找到好的解决方案。我有一个在组件中按下按钮时调用的函数,基本情况如下所示。

<script>
import tick from 'svelte'

let x = 0;
let y = 0;
let z = 0;
async function buttonHandler() {
     --- multiple computationally intensive loops 
        that update the vars x,y,z at different points ---
    e.g.
    for (a in arr) {

        x ++;
        await tick();
    }
}
</script>

<main>
    <button on:click={buttonHandler}>Click Me</button>
    <p>{x}</p>
    <p>{y}</p>
    <p>{z}</p>
</main>

我基本上希望 x、y、z 值随着函数递增而在屏幕上更新,以便实时更新进度。最初他们在函数完成之前不会更新,我读到这是因为 svelte 批量更新更改为反应变量。然后我读到 'tick()' 函数是为这种情况设计的,'flush' 更新并让 DOM 重新呈现更新的值。然而,这仍然不起作用,我让它工作的唯一方法是用通用的 sleep() 函数替换 tick() :

function sleep(millisec = 0) {
        return new Promise((resolve, reject) => {
        setTimeout(_ => resolve(), millisec);
        });
    };

这似乎不是一个好的解决方案,我觉得我一定遗漏了一些东西。有没有其他人遇到过 tick 没有按预期工作的情况?

您可以使用 afterUpdate 功能来检查您是否按预期冲洗

import { tick, afterUpdate } from 'svelte';

afterUpdate(() => {
//This should log multiple times, one for every expected value change after tick()
 console.log(x, y ,z);
})

我在 REPL 中尝试了您的代码,添加了每 100 次循环更新一次的基本循环,它看起来仍然是即时的,但日志显示它确实更新正确。所以 flush 不会像 React 那样触发新的渲染(阻塞线程),相反,它有自己的批处理计划。为了解决这个问题并保持反应,而不是看起来笨重,他们建议使用 CSS 动画来获得所需的平滑效果。 CSS 动画不会阻塞主线程。

"When you update component state in Svelte, it doesn't update the DOM immediately. Instead, it waits until the next microtask to see if there are any other changes that need to be applied, including in other components. Doing so avoids unnecessary work and allows the browser to batch things more effectively."

来自:(https://svelte.dev/tutorial/tick)[https://svelte.dev/tutorial/tick]

所以这就是为什么它在您的案例中看起来立竿见影。

你可以在这里看到他们是如何用补间动画解决这个问题的:

https://svelte.dev/tutorial/tweened

所以他们用动画减慢速度,动画不会像 setTimeoutsetInterval 或 dom 渲染那样减慢或阻塞主线程。

已更新 更好的例子在这里:https://svelte.dev/repl/c2856360456c40e98ace08438e5bf82f?version=3.38.2