#await 块在#each 循环和 DOM 刷新性能问题

#await blocks in an #each loop and DOM refresh performance issue

我循环浏览从 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 元素的重绘。关键问题是:

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

首先要做的是使用键控的每个块,这将使只有已更改的项目实际获得 re-rendered:

{#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,每次商店更改时都会 运行。 函数本身做的是:

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

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

这样做的一个缺点是你不能有一个 'loading' 指示器,尽管你可以通过使用某种 'loading' 标志将新项目推入数组然后覆盖来做到这一点他们。