【问题标题】:#await blocks in an #each loop and DOM refresh performance issue#each 循环中的 #await 块和 DOM 刷新性能问题
【发布时间】:2022-02-09 14:36:15
【问题描述】:

我正在遍历从 Sveltekit 商店检索到的项目,并异步检索每个迭代项目的附加信息。

简化后的代码如下:

        {#each $order.itemIDs as itemID}
          {#await calcItemPrice(itemID)}
          {:then price}
            {#await itemFor(itemID)}
            {:then item}
              <OrderItem itemID={item._id} description={item.description} price={price} />
            {/await}
          {/await}
        {/each}

另外,UI 允许向$order.itemIDs 添加更多条目(使用update),这会触发在每个循环中重新绘制 DOM 元素。这样做的关键问题是:

  • 每次添加项目时重绘#each 循环意味着每次都重新对每个项目进行异步调用。随着越来越多的项目被添加,这显然会影响性能。
  • 在此(缓慢)重绘期间,#each 中的 DOM 元素会闪烁,因为它们会立即消失,并在执行所有提取查询后重新出现。

我认为我的问题有两个方面:

  • 我怎样才能使添加新的itemID$order.itemIDs 不会触发所有渲染元素的重绘,而只是将新元素附加到 DOM?
  • 我应该在什么时候运行异步调用来提高渲染性能? (我感觉在渲染时运行不是最理想的)

【问题讨论】:

    标签: svelte sveltekit


    【解决方案1】:

    首先要做的是对每个块使用一个键控,这将使得只有已更改的项目实际上被重新渲染:

    {#each $order.itemIDs as itemID (itemID)}
    

    确保你使用的ID是唯一的,以上只是一个例子!


    也就是说,我不会在循环中使用 await 块,我相信这只是在寻找问题。看看是否可以将这些项目加载到其他地方,也许在第一次运行时使用等待块。

    如何实现这一点当然很大程度上取决于您的用例和要求,一个想法可能是让另一个数组从商店中填充:

    let items = []
    
    async function loadItems(stored) {
      const changed = stored.filter(s => !items.some(s => s.id == s));
      const result = await Promise.all(changed.map(async => calcsHere))
      items = [...items, ...result];
    }
    
    $: loadItems($order.itemIDs)
    

    上面的代码声明了一个数组items和一个函数loadItems,每次存储发生变化时都会运行。 函数本身的作用是:

    • 过滤掉新的项目(不重新获取它们)
    • 同时触发所有新项目的提取并等待所有新项目返回
    • 将新项目添加到旧项目中

    (请注意,我在该代码中可能有很多错误,这只是一个一般概念)

    这样做的一个缺点是您不能有一个“正在加载”指示器,尽管您可以通过使用某种“正在加载”标志将新项目推送到数组然后覆盖它们来做到这一点。

    【讨论】:

    • 谢谢,这很有用。我尝试了密钥,但它似乎在这里没有效果,可能是因为 svelte 无法确定 DOM 元素是否会由于内容的异步性质而改变?在文档中阅读,似乎默认行为是我想要的。 “如果提供了键表达式 [...] Svelte 将在数据更改时使用它来区分列表,而不是在末尾添加或删除项目。”我将尝试 loadItems 函数按照建议,然后回到这里。
    • 提示:indicator = Promise.all(...); const result = await indicator;允许显示带有 {#await indicator}Loading...{/if} 的微调器
    猜你喜欢
    • 2012-08-06
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多