Fiber reconciliation

Fiber reconciliation ikki bosqichda amalga oshiriladi: *render(tayyorlash) *bosqichi va commit(o’zgarishlarni tatbiq qilish) bosqichi. Ushbu ikki bosqichli yondashuv (rasmda ko’rsatilgan) React’ga, DOM’ga qo’shilishdan va foydalanuvchilarga yangi holatni ko’rsatishdan oldin har qanday vaqtda bekor qilinishi mumkin bo’lgan renderlash ishini bajarish imkonini beradi: bu renderlashni to’xtatib qo’yadigan qiladi. Biroz batafsilroq aytadigan bo’lsak, renderlashni to’xtatib qo’yadigan narsa bu React rejalashtiruvchisi(scheduler) tomonidan har 5 msda bajarishni asosiy thread(main thread)ga qaytarishning g’ayrioddiy yondashuvi bo’lib, bu hatto 120 fps (kadr/sekund) tezlikdagi qurilmalarda ham bitta kadrlashdan kichikroqdir.

Fiber reconciler’da reconciliation oqimi

Biz kelgusi boblarda React’ning concurrent(bir vaqtda ishlashlik) xususiyatlarini o’rganayotganda scheduler’ning tafsilotlariga chuqurroq kiramiz. Ammo hozircha, reconciliation’ning ushbu bosqichlarini ko’rib chiqamiz.

Render bosqichi (render phase)

Render bosqichi joriy daraxtda state o’zgarishi hodisasi sodir bo’lganda boshlanadi. React o’zgarishlarni alternativ daraxtda, ekrandan tashqarida, har bir Fiber’ni rekursiv ravishda bosqichma-bosqich ko’rib chiqish va yangilanishlar kutilayotganligini bildiruvchi bayroqlarni o’rnatish orqali amalga oshiradi (rasmga qarang). Yuqorida aytib o’tilganidek, bu jarayon React ichida beginWork deb nomlangan funksiyada sodir bo’ladi.

Render bosqichining chaqiruv tartibi

beginWork

beginWork hali ish jarayonida bo’lgan(in-progress) daraxtdagi Fiber tugunlarida ular yangilanishi kerakmi yoki yo’qligini bildiruvchi bayroqlarni o’rnatish uchun javobgardir. Bu bir nechta bayroqlarni o’rnatadi va keyin navbatdagi Fiber tugunga o’tib, daraxtning oxiriga yetguncha shu ishni davom ettiradi. Bu tugagandan so’ng, Fiber tugunlarida completeWork funksiyasi chaqirila boshlanadi va yuqoriga qarab harakat qilinadi.

beginWork funksiyasining ko’rinishi quyidagicha:

function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null;

completeWork haqida keyinroq batafsil ma’lumot beriladi. Hozircha, beginWork funksiyasini ko’rib chiqamiz. Uning ko’rinishida quyidagi argumentlar mavjud:

current

Joriy daraxtdagi hali ish jarayonida bo’lgan tugunga mos keladigan Fiber tuguniga havola. Bu daraxtning avvalgi va yangi versiyasi o’rtasida qanday o’zgarishlar bo’lganligini aniqlash va nimalarni yangilash kerakligini belgilash uchun ishlatiladi. Bu hech qachon o’zgartirilmaydi va faqat taqqoslash uchun ishlatiladi

workInProgress

Hali ish jarayonida bo’lgan yangilanayotgan Fiber tuguni. Bu tugun yangilangan taqdirda “ifloslangan” deb belgilanadi va funksiya tomonidan qaytariladi.

renderLanes

Render lanes(render yo’llari) — bu React’ning Fiber reconciler’ida yangi tushuncha bo’lib, eski renderExpirationTimeni o’rnini egallaydi. Bu eski renderExpirationTime tushunchasiga nisbatan biroz murakkabroq, ammo React’ga yangilanishlarni yaxshiroq ustuvorlashtirish va yangilanish jarayonini samaraliroq qilish imkonini beradi. renderExpirationTime eskirganligi sababli, biz bu bobda renderLanesga e’tibor qaratamiz.

Render yo’l(lane)lari asosan yangilanishlar ishlov berilayotgan “yo’l(lane)lar”ni ifodalovchi bitmask’dir. Yo’llar yangilanishlarni ularning ustuvorligi va boshqa omillar asosida tasniflashning bir usulidir. React komponentida o’zgarish amalga oshirilganda, bu o’zgarish uning ustuvorligi va boshqa xususiyatlariga qarab bir yo’lga tayinlanadi. O’zgarishning ustuvorligi yuqori bo’lsa unga yuqori yo’l, ya’ni lane, beriladi.

Yangilanishlar to’g’ri tartibda ishlanishini ta’minlash uchun renderLanes qiymati beginWork funksiyasiga uzatiladi. Yuqori ustuvorlikka ega yo’llarga tayinlangan yangilanishlar, past ustuvorlikka ega yo’llarga tayinlangan yangilanishlardan avval ishlov beriladi. Bu, foydalanuvchi bilan interaktivlik yoki foydalanish imkoniyati qulayligi(accessibility) kabi yuqori ustuvorlikdagi yangilanishlarning iloji boricha tezroq ishlov berilishini ta’minlaydi.

Yangilanishlarni ustuvorlashtirishdan tashqari, renderLanes React’ga konkurentlikni, ya’ni bir vatda ishlashni, yaxshiroq boshqarishga ham yordam beradi. React uzun davom etadigan yangilanishlarni kichik, boshqarish oson bo’lgan bo’laklarga ajratish uchun “vaqtni bo’lish”(time slicing) deb ataladigan texnikadan foydalanadi. renderLanes bu jarayonda muhim rol o’ynaydi, chunki bu React’ga qaysi yangilanishlar birinchi bo’lib ishlov berilishi kerakligini va qaysi yangilanishlar keyinroqqa kechiktirilishi mumkinligini aniqlash imkonini beradi.

Render bosqichi tugagach, getLanesToRetrySynchronouslyOnError funksiyasi render bosqichida qachondir kechiktirilgan yangilanishlar yaratilganligini aniqlash uchun chaqiriladi. Agar kechiktirilgan yangilanishlar bo’lsa, updateComponent funksiyasi yangi ish siklini boshlaydi, beginWork va getNextLanesdan foydalanib, yangilanishlarni ishlov berish va ularni yo’llariga ko’ra ustuvorlashtirish uchun.

Biz “Render Lane”’lar haqida kelgusi bobda yanada chuqurroq o’rganamiz. Hozircha, Fiber reconciler oqimini davom ettiraylik.

completeWork

completeWork funksiyasi hali tugallanmagan bo’lgan Fiber tuguniga yangilanishlarni qo’llaydi va ilovaning yangilangan holatini ifodalovchi yangi real DOM daraxtini yaratadi. Ushbu daraxt brauzer ko’rinishidan tashqarida, DOM bilan bog’lanmagan holda quriladi.

Agar asosiy muhit brauzer bo’lsa, bu document.createElement yoki newElement.appendChild kabi ishlarni bajarishni anglatadi. Yodda tuting, ushbu elementlar daraxti hali brauzerdagi dokument bilan bog’lanmagan: React shunchaki UI’ning navbatdagi versiyasini ekran tashqarisida yaratmoqda. Bu ishni ekran tashqarisida bajarish uni to’xtatiluvchan qiladi: React hisoblayotgan navbatdagi holat hali ekranga chizilmagan, shuning uchun yuqori ustuvorlikka ega yangilanish rejalashtirilsa, uni bekor qilish mumkin. Bu Fiber reconciler’ning asosiy maqsadi.

completeWork funksiyasining tuzilishi quyidagicha:

function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null;

Bu yerda, beginWork bilan bir xil tuzilish mavjud.

completeWork funksiyasi beginWork funksiyasiga yaqin bo’lib, beginWork Fiber tugunidagi “yangilanish kerakmi” holati haqida bayroqlarni o’rnatish uchun javobgar bo’lsa, completeWork yangi daraxtni yaratib, uni asosiy host muhitga kiritish uchun javobgardir. completeWork yuqoriga yetib, yangi DOM daraxtini yaratgandan so’ng, “render bosqichi tugallandi” deb aytiladi. Endi React commit bosqichiga o’tadi.

Commit bosqichi (commit phase)

Commit(tatbiq qilish) bosqichi (rasmga qarang) real DOM’ni render bosqichida virtual DOM’ga kiritilgan o’zgarishlar bilan yangilash uchun javobgardir. Commit bosqichi davomida yangi virtual DOM daraxti asosiy host muhitga kiritiladi va hali tugallanmagan daraxt joriy daraxt bilan almashtiriladi. Shu bosqichda barcha effektlar ham bajariladi. Commit bosqichi ikki qismga bo’linadi: mutatsiya bosqichi va layout bosqichi.

FiberRootNode bilan commit bosqichi

Mutatsiya bosqichi (mutation phase)

Mutatsiya bosqichi — bu commit, ya’ni tatbiq qilish, qo’llash, bosqichining birinchi qismi bo’lib, virtual DOM’ga kiritilgan o’zgarishlarni real DOM’ga yangilash uchun javobgardir. Ushbu bosqichda React yangilanishlar kerakligini aniqlaydi va commitMutationEffects deb nomlangan maxsus funksiyani chaqiradi. Bu funksiya render bosqichida alternativ daraxtdagi Fiber tugunlariga kiritilgan o’zgarishlarni real DOM’ga qo’llaydi.

Bu yerda, commitMutationEffects qanday amalga oshirilishi mumkinligini to’liq psevdokod misolida ko’rsatamiz:

function commitMutationEffects(Fiber) {
  switch (Fiber.tag) {
    case HostComponent: {
      // DOM tugunini yangi props va/yoki children bilan yangilash
      break;
    }
    case HostText: {
      // DOM tugunining tekst kontentini yangilash
      break;
    }
    case ClassComponent: {
      // Lifecycle metodlari, masalan, componentDidMount va componentDidUpdate chaqiriladi
      break;
    }
    // ... boshqa turdagi tugunlar uchun holatlar
  }
}

Mutatsiya bosqichi davomida React shuningdek, commitUnmount va commitDeletion kabi maxsus funksiyalarni ham chaqiradi, bu funksiyalar DOM’dan endi kerak bo’lmagan tugun(node)larni olib tashlash uchun ishlatiladi.

Layout bosqichi (layout phase)

Layout(joylashuv) bosqichicommit bosqichining ikkinchi qismi bo’lib, DOM’dagi yangilangan tugunlarning yangi joylashuvlarini hisoblash uchun mas’uldir. Ushbu bosqichda React commitLayoutEffects deb nomlangan maxsus funksiyani chaqiradi. Bu funksiya DOM’dagi yangilangan tugunlarning yangi joylashuvlarini hisoblab chiqadi.

commitMutationEffects kabi, commitLayoutEffects ham turli tugunlar yangilanishiga qarab har xil funksiyalarni chaqiradigan katta “switch statement”ga ega.

Layout bosqichi yakunlangandan so’ng, React real DOM’ni render bosqichida virtual DOM’ga kiritilgan o’zgarishlarga mos ravishda muvaffaqiyatli yangilaydi.

Commit bosqichini ikki qismga — mutatsiya va layout’larga ajratish orqali React DOM’ga yangilanishlarni samarali tarzda qo’llaydi. Reconciler’dagi boshqa asosiy funksiyalar bilan hamkorlikda ishlash orqali commit bosqichi React ilovalari murakkablashib, katta miqdordagi ma’lumotlarni qayta ishlashiga qaramay, tez, javob beruvchan va ishonchli bo’lishini ta’minlaydi.

Effektlar (effects)

React’ning reconciliation jarayonining commit bosqichida “side effect”lar o’ziga xos tartibda, effektning turiga qarab bajariladi. Commit bosqichida sodir bo’lishi mumkin bo’lgan bir nechta effektlar mavjud:

  • Joylashtirish effektlari (Placement effects): Bu effektlar yangi komponent DOM’ga qo’shilganda yuz beradi. Masalan, agar forma ichiga yangi tugma(button) qo’shilsa, tugmani DOM’ga qo’shish uchun ushbu joylashtirish effekti sodir bo’ladi.
  • Yangilash effektlari (Update effects): Bu effektlar komponent yangi props yoki state bilan yangilanganda yuz beradi. Masalan, agar tugmaning teksti o’zgarsa, tekstni DOM’da yangilash uchun yangilash effekti sodir bo’ladi.
  • O’chirish effektlari (Deletion effects): Bu effektlar komponent DOM’dan o’chirilganda yuz beradi. Masalan, agar forma ichidagi tugma olib tashlansa, tugmani DOM’dan olib tashlash uchun o’chirish effekti sodir bo’ladi.
  • Layout(joylashuv) effektlari (Layout effects): Bu effektlar brauzer ekranga chizish imkoniyatiga ega bo’lmasdan oldin sodir bo’ladi va sahifaning joylashuvi, ya’ni layout’ini, yangilash uchun ishlatiladi. Layout effektlari funksional komponentlarda useLayoutEffect hook’i va class komponentlarda componentDidUpdate lifecycle metodi orqali boshqariladi.

Commit bosqichidagi ushbu effektlardan farqli o’laroq, passiv effektlar ham mavjud. Passiv effektlar — bu foydalanuvchi tomonidan belgilanadigan effektlar bo’lib, brauzer ekranga chizish imkoniyatiga ega bo’lgandan keyin bajariladi. Passiv effektlar useEffect hook’i orqali boshqariladi.

Passiv effektlar sahifaning dastlabki chizilishida muhim bo’lmagan harakatlarni amalga oshirish uchun foydalidir, masalan, API’dan ma’lumot olish yoki analitika kuzatuvini amalga oshirish. Passiv effektlar render bosqichida bajarilmaganligi sababli, foydalanuvchi interfeysini dasturchi istagan holatga olib kelish uchun minimal yangilanishlar to’plamini hisoblash vaqtiga ta’sir qilmaydi.

Hamma narsani ekranga chiqarish

React ikkita daraxtdan biriga ishora qiluvchi FiberRootNode deb nomlangan yuqori darajadagi tugunni boshqaradi: bu current yoki workInProgress daraxtlari bo’lishi mumkin. FiberRootNode — reconciliation jarayonining commit bosqichini boshqarish uchun javob beradigan muhim ma’lumotlar strukturasi hisoblanadi.

Virtual DOM’ga o’zgarishlar kiritilganda, React workInProgress daraxtini yangilaydi, lekin current daraxtini o’zgarishsiz qoldiradi. Bu React’ga virtual DOM’ni render qilish va yangilashni davom ettirish imkonini beradi, shu bilan birga dastur holatining hozirgi holatini saqlaydi.

Render jarayoni tugagach, React commitRoot deb nomlangan funksiyani chaqiradi, bu funksiya workInProgress daraxtida amalga oshirilgan o’zgarishlarni real DOM’ga kiritish uchun javobgardir. commitRoot funksiyasi FiberRootNode ko’rsatkich ishorasi(pointer)ni joriy daraxtdan workInProgress daraxtiga o’zgartiradi, natijada workInProgress daraxti yangi joriy daraxt bo’lib qoladi.

Shundan so’ng, kelgusidagi barcha yangilanishlar yangi joriy daraxtga asoslanadi. Bu jarayon dastur holatining izchil qolishini va o’zgarishlarning to’g’ri va samarali tarzda qo’llanilishini ta’minlaydi.

Bularning barchasi brauzerda deyarli darhol sodir bo’lgandek tuyuladi. Bu — “reconciliation jarayoni”ning natijasidir.