我正在《Elm 指南》中阅读有关优化的内容。它讨论了键控节点,以美国总统为例:
import Html exposing (..)
import Html.Keyed as Keyed
import Html.Lazy exposing (lazy)
viewPresidents : List President -> Html msg
viewPresidents presidents =
Keyed.node "ul" [] (List.map viewKeyedPresident presidents)
viewKeyedPresident : President -> (String, Html msg)
viewKeyedPresident president =
( president.name, lazy viewPresident president )
viewPresident : President -> Html msg
viewPresident president =
li [] [ ... ]
Run Code Online (Sandbox Code Playgroud)
然后给出这个作为解释:
现在,虚拟 DOM 实现可以识别何时重新排列列表。它首先通过密钥匹配所有总统。然后它区分这些。我们对每个条目都使用了惰性,因此我们可以跳过所有这些工作。好的!然后它会弄清楚如何打乱 DOM 节点以按照您想要的顺序显示内容。所以键控版本最终要做的工作要少得多。
我的困惑是:如果我不在lazy键控节点内部使用,虚拟 DOM 仍然必须比较列表中的每个条目,即使它可以匹配某些键。看来键控节点的有用性确实取决于lazy内部。我的理解正确吗?
让我们考虑一个例子:
现在我们假设用户按价格排序:
如果没有键控节点,差异将如下所示:
在此示例中,将发出 9 个replaceElement操作和 9 个createTextElement操作(例如,确切的语义可能略有不同,但我认为这一点是正确的)。
键控版本将了解订单已更改,并将为苹果节点发出单个removeChild和。appendChild
因此,所有性能节省都在 DOM 方面。现在,这不仅仅是为了性能,如果这些列表有输入元素,如果您将光标放在 Apple 输入中,则保持它们处于键入状态,它将保留在 Apple 输入中,但如果它们没有键入,那么它现在将位于香蕉输入。
你是对的,如果没有懒惰,差异仍然会发生,但差异通常是便宜的部分,更昂贵的部分实际上是修补 DOM,这是 keyed 有助于防止的。