0

我正在尝试限制Svelte 中函数的执行。但是,在自动订阅中使用节流阀似乎会破坏它。考虑以下示例(REPL):

<script>
  import throttle from 'lodash.throttle';
  import { writable } from 'svelte/store';
    
  const arr = writable(['A', 'B', 'C']);
    
  function foo(val) {
    console.log('foo: ', val);
  }
</script>

{#each $arr as a}
  <button on:click={throttle(() => { foo(a); }, 1000)}>
    Button {a}
  </button>
{/each}

的执行foo(a)根本没有受到限制。如果您删除该{#each $arr as a}块并将一个字符串传递给 foo,您将看到它按预期工作。

我假设这与事件循环以及 Svelte 自动订阅如何工作有关,但不知道确切原因。想知道是否有人知道a)为什么会发生这种情况以及b)可能的解决方案是什么样的?

4

1 回答 1

1

如果您查看 Svelte 为此生成的代码,您可以看到当您传递存储值时,它会在每次单击时重新生成节流函数。这会在每次点击时重置油门计时器。

dispose = listen(button, "click", function () {
    if (is_function(throttle(click_handler, 1000))) 
        throttle(click_handler, 1000).apply(this, arguments);
});

无论出于何种原因,当您传递常规字符串时都不会发生这种情况。

dispose = listen(button, "click", throttle(click_handler, 1000));

这可能是 Svelte 中的一个错误,但我不确定。在GitHub 存储库上打开一个问题可能是值得的。

我能够通过提前生成节流函数来解决它:

<script>
    import throttle from 'lodash.throttle';
    import { writable } from 'svelte/store';
    
    const arr = writable(['A', 'B', 'C']);
    
    function foo(val) {
        console.log('foo: ', val);
    }
    
    $: throttledFns = $arr.map(val => getThrottled(val));
    
    function getThrottled(val) {
        console.log('getting throttled');
        return throttle(() => { foo(val); }, 1000);
    }
</script>

{#each $arr as a, idx}
    <button on:click={throttledFns[idx]}>
        Button {a}
    </button>
{/each}

这将在存储数组更改时重新生成受限制的函数,但不是在每次单击时。

您也可以一次生成 foo 的限制版本并使用它,但这会限制对按钮的所有点击(例如,如果您点击 A 然后点击 B,对 B 的点击将被限制)。

<script>
    // as before
    
    const throttledFoo = throttle(foo, 1000);
</script>

{#each $arr as a, idx}
    <button on:click={() => throttledFoo(a)}, 1000)}>
        Button {a}
    </button>
{/each}
于 2021-03-30T15:42:01.870 回答