پرش به محتویات

Html.Keyed

در بخش قبل، یاد گرفتیم که Virtual DOM چگونه کار می‌کند و چگونه می‌توانیم از Html.Lazy برای جلوگیری از کارهای زیاد استفاده کنیم. اکنون می‌خواهیم Html.Keyed را معرفی کنیم تا کارهای بیشتری را نادیده بگیریم.

این نوع بهینه‌سازی، برای فهرست داده که باید از عملیات درج، حذف و مرتب‌سازی پشتیبانی کند، بسیار مفید است.

مشکل

فرض کنید فهرستی از تمام رییس جمهورهای ایالات متحده داریم. شاید این امکان را به ما بدهد تا بر اساس نام، تحصیلات، دارایی خالص و محل تولد آن را مرتب‌سازی کنیم.

زمانی که الگوریتم تفاوت‌گذاری (که در بخش قبل توضیح داده شد) به یک فهرست طولانی از اقلام می‌رسد، به صورت جفت جفت پیش می‌رود:

  • تفاوت عنصر اول فعلی با عنصر اول بعدی.
  • تفاوت عنصر دوم فعلی با عنصر دوم بعدی.
  • تفاوت عنصر سوم فعلی با عنصر سوم بعدی.
  • ...

اما وقتی ترتیب مرتب‌سازی را تغییر می‌دهید، همه این‌ها متفاوت خواهند بود! بنابراین در DOM کار زیادی انجام می‌دهید در حالی که می‌توانستید فقط برخی از عناصر را جابجا کنید.

این مشکل همچنین برای عملیات درج و حذف نیز وجود دارد. فرض کنید اولین مورد از ۱۰۰ مورد را حذف می‌کنید. همه چیز یک واحد جابجا می‌شود و متفاوت بنظر می‌رسد. بنابراین، در انتها ۱ مورد حذف و ۹۹ مورد تفاوت‌گذاری خواهید داشت. اصلا خوب نیست!

راه حل

مشکل بالا، با استفاده از تابع Html.Keyed.node قابل حل است. تابع این امکان را فراهم می‌کند تا هر ورودی را با یک "کلید" جفت کنیم که براحتی آن را از سایرین متمایز می‌کند.

بنابراین، در مثال رییس جمهور، می‌توان کد را به این صورت بازنویسی کرد:

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 [] [ ... ]

هر عنصر فرزند، با یک کلید مرتبط است. بجای تفاوت‌گذاری جفت جفت، می‌توانیم بر اساس کلیدهای موجود تفاوت‌گذاری کنیم!

اکنون پیاده‌سازی Virtual DOM می‌تواند تشخیص دهد که فهرست داده دوباره مرتب شده است. ابتدا همه رییس جمهورها را بر اساس کلید مطابقت می‌دهد، سپس آن‌ها را مقایسه می‌کند. از تابع lazy برای هر ورودی استفاده کردیم، بنابراین می‌توانیم از تمام آن کارها صرف‌نظر کنیم. بسیار خوب! سپس مشخص می‌کند که چگونه عناصر DOM را جابجا کند تا چیزها را به ترتیبی که می‌خواهید نشان دهد. در نهایت، نسخه مبتنی بر کلید، کار بسیار کمتری انجام می‌دهد.

مرتب‌سازی مجدد، به درک بهتر از چگونگی انجام کار کمک می‌کند، اما رایج‌ترین موردی نیست که واقعا به این بهینه‌سازی نیاز دارد. عناصر مبتنی بر کلید برای عملیات درج و حذف بسیار مهم هستند. وقتی اولین مورد از ۱۰۰ عنصر را حذف می‌کنید، استفاده از این تکنیک به پیاده‌سازی Virtual DOM اجازه می‌دهد که بلافاصله آن عنصر را تشخیص دهد. بنابراین، ۱ مورد حذف بجای ۹۹ مورد تفاوت‌گذاری خواهید داشت.

خلاصه

دستکاری DOM در مقایسه با انواع محاسباتی که در یک وب اپلیکیشن انجام می‌شود، بطور وحشتناکی کُند است. همیشه، در ابتدای کار به توابع Html.Lazy و Html.Keyed مراجعه کنید. توصیه می‌کنم این کار را با پروفایل‌گیری تا حد امکان تایید کنید. برخی از مرورگرها، مانند کروم نمای زمانی از برنامه ارایه می‌دهند. این ویژگی، یک نمای کلی از زمان صرف شده در بارگیری، اسکریپت‌نویسی، رِندر و ترسیم عناصر برنامه را فراهم می‌کند. اگر می‌ببینید که ۱۰٪ از زمان صرف اسکریپت‌نویسی می‌شود، می‌توانید کد Elm را دو برابر سریع‌تر کنید و هیچ تفاوت قابل توجهی ایجاد نکنید. در حالی که، استفاده از توابع lazy و keyed می‌تواند بخش بزرگی از آن ۹۰٪ دیگر را با دستکاری کمتر DOM کاهش دهد!