کار با DOM مهمترین بخش وب مدرن و تعاملی است، اما متأسفانه کندتر از اکثر عملیاتهای جاوا اسکریپت است و این واقعیت که اکثر فریمورکهای جاوا اسکریپت، DOM را بسیار بیشتر از آنچه لازم است بهروزرسانی میکنند، آن را بسیار کندتر میکند.
فرض کنید فهرستی دارید که شامل ده مورد است و شما اولین مورد را بررسی میکنید. اکثر فریمورکهای جاوا اسکریپت کل لیست را بازسازی میکنند و این ده برابر بیشتر از آن چیزی که لازم است کار میبرد. با وجود اینکه فقط یک مورد تغییر کرده است، ۹ مورد باقیمانده نیز دقیقاً همان طور که قبلاً بودند بازسازی میشوند.
بازسازی یک لیست برای یک مرورگر وب مسئله مهمی نیست، اما وبسایتهای مدرن از مقادیر زیادی کار با DOM استفاده میکنند. هرچه اجزای رابط کاربری بیشتری در صفحه وجود داشته باشد، بهروزرسانیهای DOM پرهزینهتر خواهند بود؛ زیرا همه اجزای رابط کاربری در هر بهروزرسانی DOM، دوباره رندر میشوند.
پس وجود چه چیزی React را سریع کرده است؟ برای رفع مشکلی که در بالا به آن اشاره کردیم، تیم React مفهومی به نام DOM مجازی (Virtual DOM) را معرفی کرد. از آنجایی که React از DOM مجازی استفاده میکند، به اندازه کافی هوشمند است تا تنها آیتم بررسیشده در لیست را بازسازی کند و بقیه لیست را دستنخورده باقی بگذارد. شهرت React در کارایی از این ویژگی مطلوب آن ناشی میشود. تا انتهای این مطلب از کوئرا بلاگ همراه ما باشید تا شما را بیشتر با این مفهوم آشنا کنیم.
مانند DOM واقعی، DOM مجازی فقط یک درخت گره است که عناصر و خصوصیات (attribute) و محتوای آنها را بهعنوان اشیا (object) و ویژگیها (properties) فهرست میکند. هنگامی که عناصر جدید به UI اضافه میشوند، یک DOM مجازی جدید ایجاد میشود که در آن هر عنصر یک گره در درخت است.
هنگامی که یک عنصر JSX را رندر میکنید، تک تک اشیا در DOM مجازی بهروز میشوند. این ممکن است ناکارآمد به نظر برسد، اما از آنجایی که DOM مجازی میتواند خیلی سریع بهروز شود، هزینه آن ناچیز است. DOM مجازی میتواند در هر ثانیه ۲۰۰,۰۰۰ گره تولید کند.
React و DOM مجازی
پس از تغییر وضعیت در هر یک از عناصر شما و ایجاد یک درخت DOM مجازی جدید، این درخت با تصویری از DOM قبلی که درست قبل از بهروزرسانی گرفته شده است، مقایسه یا diff میشود.
در ریاکت، ()render نقطهای است که در آن UI بهروز و رندر میشود، اما همچنین نقطهای است که این درخت از عناصر ساخته میشود. هنگامی که یک وضعیت یا prop در یک کامپوننت بهروز میشود، ()render یک درخت تازه برمیگرداند؛ فرایندی مشابه با فراخوانی ()setState.
React منطق خود را برای آنچه باعث ایجاد رندرهای مجدد میشود، در نهایت سادگی حفظ میکند: اگر یک گره متفاوت باشد (خواه به دلیل متفاوت بودن نوع آن یا متفاوت بودن کامپوننت) کل زیردرخت را دوباره رندر میکند.
هنگامی که مقایسه انجام شد، React دقیقاً میداند کدام گرههای DOM مجازی تغییر کردهاند. سپس همان گرهها در DOM واقعی بهروزرسانی میشوند؛ اما فقط آن گرههای خاصی که تغییر کردهاند و نه یک رندر کامل.
اما React چگونه درختها را مقایسه میکند و تغییراتی را برای درج در DOM واقعی پیدا میکند؟
پس از اینکه درختها ساخته شدند، React درخت را برای یافتن تغییرات در مقایسه با درخت قدیمی بررسی یا diff میکند. الگوریتم Diffing بسیار ساده و بر اساس دو فرض زیر است:
دو عنصر از انواع مختلف، درختان متفاوتی را تولید خواهند کرد.
شما میتوانید با یک key prop متوجه شوید که کدام عناصر فرزند ممکن است در رندرهای مجدد ثابت باشند.
اگر عنصرِ ریشهی DOM متفاوت باشد، الگوریتم Diffing درخت قدیمی را کاملاً از بین میبرد و از ریشه، درخت جدید را شروع میکند. برعکس، اگر عنصر ریشهی DOM تغییر نکرده باشد، آنگاه الگوریتم، همه تفاوتها در خصوصیات را مقایسه میکند، خصوصیات بدون تغییر را حفظ میکند و فقط خصوصیات جدید و تغییریافته را تغییر میدهد.
سپس هنگامی که یک عنصر، حاوی چندین گره فرزند (یک سری از عناصر <li>) باشد، React به طور همزمان تفاوتها را مرحلهبهمرحله بررسی میکند. اگر تفاوت در گرههای فرزند در انتها باشد، عنصرِ اضافهشده به عنوان تنها بهروزرسانی ذکر میشود. اما اگر عنصری در ابتدا اضافه شده باشد، همه فرزندان بعدی نیز برای بهروزرسانی نشانهگذاری میشوند. برای حل این مشکل، React یک خصوصیت کلیدی را پیادهسازی کرد که هنگام مقایسه از آن برای مطابقت فرزندان استفاده میکند.
مورد دیگری که عملکرد React را افزایش میدهد این است که در واقع React لیستی از همهی این تغییراتِ لازم برای DOM را جمعآوری میکند و سپس آنها را در یک دسته ارسال میکند. این کار برای جلوگیری از تصویرسازی مجدد UI توسط DOM مرورگر انجام میشود، زیرا این پرهزینهترین و ناکارآمدترین بخش بهروزرسانیهای DOM است. به جای ارسالِ بهروزرسانیها برای هر تغییر حالت، تغییرات در یک دسته به DOM ارسال میشوند تا اطمینان حاصل شود که رویداد تصویرسازی مجدد، فقط یک بار انجام میشود.
React آگاهانه الگوریتم خود را به این سادگی حفظ کرده است تا بازده زمانی را بهینه کند و در عین حال عملکرد را در سطحی تقریباً یکسان با برخی از الگوریتمهای پیشرفته حفظ کند. سازندگان React خاطرنشان میکنند که در حالی که الگوریتمهای پیشرفته میتوانند منجر به افزایش عملکرد اندکی شوند، اما در مقایسه با زمانِ خطیِ الگوریتمِ سادهی آنها O(n)، پیچیدگیهایی از مرتبه O(n³) دارند.
جمعبندی
کار با DOM مرورگر ذاتاً کند نیست، این تصویرسازیِ آنها از رابط کاربری است که پرهزینه است. DOM مجازی React با اطمینان از اینکه فقط عناصری که باید در DOM تغییر کنند دستکاری شدهاند و اینکه این بهروزرسانیها به صورت دستهای ارسال میشوند، این رویدادهای تصویرسازی را به حداقل میرساند. این دسته از بهروزرسانیها از رویدادهای تصویرسازیِ غیرضروری، جلوگیری و برنامههای React را کارآمدتر میکند.
در این مقاله بررسی کردیم که چه چیزی React را سریع کرده است. خوشحال میشویم تا نظر خود را درباره این مطلب با ما به اشتراک بگذارید.