Адказы на спрабоўкі на React і JavaScript, якія паказваюць сапраўдную глыбіну.
Адзёрнайце сильнейшыя, более дэталізаваныя адказы на частыя запитанні пад час спрабоўк на React і JavaScript – ад Virtual DOM да проектавання системы – якія паказваюць глыбокі інжынерны суджэнне.
Вступ: Чаму большасць кандыдаўтаў звучаюць аднакова
Якщо прынясці участь у достатнім ліку спэвачых на React, можна зазначыць певную законамірнасць: тыя ж самыя стандартныя фразы павтараюцца знову і зноў. «Virtual DOM працюе быстрэй». «useEffect выкорыстоўваецца для парагонных эфектаў». «JavaScript працюе на аднай ніткі». Ніякая з гэтых твердзенняў не ёсць некалькі, але гэта тыя речы, якія кожны можа запам’ятаваць пасля швыдкага прачытання калькі пастаў, і яны нічога не розпаведаюць спэвачаму пра тое, як вы на самай працоўцы размышляеце.
Тое, што адзначае сильнага кандыдаўта ў аднасоўці да таго, хто отрымае ввічлівы лист з адмовай, — гэта не тое, чыі ён знае канцептуальную дэфініцыю, а тое, чыі ён можа зайсці на адны слой глэбей. Чы можаце вы павязаць канцэпцію з альтернатывамі, якія стояць за ёю? Чы можаце вы поясніць, чаму была прынята тая чы іншая дыяктара, а не проста які ёй эфект? Гэта тое, што на самай працоўцы шукаюць спэвачы.
У гэтым кялічыку рассказваецца пра пытанні, якія насправдзе вылучаюцца пад час спытанняў на ролях среднага і высокага рангу ў сферы фронтэнд-разработкі, а таксама даўаюцца адпаведныя адказы, дастаткова дакладныя, каб спытальнік перестаў прыглядацца да своіх нотатак і адчувальна слухаў.
Раздзіл 1: Асновныя концэпцыі React
Пытанне 1: «Адказайце, што такое Вярчыны ДОМ. Как яно працюе?»
Забываемы адказ: «Вярчыны ДОМ — это лёгкая копія рэальнага ДОМ. React паруе іх і апдейтуе толькі тое, што змянілася, чыяму і ўскорае працэс.»
Болей дакладны адказ: Вярчыны ДОМ — это абстракцыя, але якш толькі называць яго «ускораннем», то не усвіядомляецца справжняя сутнасць. Рэальная выгода ў продуктывасці не выходзіць з самага Вярчыны ДОМ — яна выходзіць з логікі групавання і супрацоўкі данных, створанай навакол яго.
React внутршняя частка стежыць за двумя дрэвамі: тым, яны выклікаюцца на экране, і дрэвам у стадіи стварэння, якое прадстаўляе тое, што будзе адрасавана. Калі змянюецца стан, React не спешыць зараз жа прабавіцца змяніць рэальны DOM. У замест на гэта ён стварае новае дрэва Virtual DOM, адрабатвае процедуру пораўнання, каб выявіць мінімальны набор неабходных змян, а пасля прыкладзець усі гэтыя змяны да рэальнага DOM адразу, у ўсіх разам. Саме гэты крок батчавання запобегае падзейню разовых перыяканняў лэйауту, якія часта называюцца layout thrashing.
Є ўсё ж адна нюанс, якую варта згадаць: Virtual DOM — гэта не безкоштовны рыянак. Його алгорытм разлічэння навмесна падтрымваецца на сложнасці O(n) за дапамою гіурыстык — напрыклад, прыпускаючы, што элементы розных типаў створуюць абсалютна разныя паддрэвы — замест таго, каб выконваць абсалютна загальны алгорытм разлічэння дрэва з сложнасцю O(n³). Гэты компроміс дапамагае падтрымваць высокую швальнасць у звычных ситуаціях, але гэта значыць, што певныя сценарыі, такія як вельмі большы список, дзе зменіваецца толькі адны элемент, можа ўсё ж заставіць працюваты систему з вялікіми зусіллямі. Самэй гэтага існуюць такія інструменты, як React.memo, useMemo, а таксама бібліятэкі для віртуалізацыі списакоў.
Таксама варта адзначыць, што Вярчыны ДОМ трапляецца втрачаць частку свайго прыемнасці як унікальная перавага. Кампайляры, такія як Svelte, зовсім прахоцяюць крок з Вярчыным ДОМ, а сам React працюе над функцыямі паралельнай відраслі, якія зменшуюць спосаб, у які фактычна супрацоўка адбываецца. Вярчыны ДОМ рашыў конкрэтную проблему адносна 2013 года. Розумеў, чаму яго спачатку было введзена, мае большое значэнне, чым можлівасць пераказаць тэхнічныя аспекты.
Такой спосаб адпаведзення працюе, таму што ён паказвае архівную усведамленасць, чыстае адзначэнне компромісаў і знаёмства з тым, як эвалюаваецца шырэйшы фронтэнд-ландшафт — вы не проста адпавядаеце на буквальны вопыт, вы паказваеце, што розумееце, дзе гэя ідея паследуе ў большай кантэксты.
Вопыт 2: «У чым разлік межу useEffect, useLayoutEffect і калі вы бы вжылі кожны з іх?»
Забываемая адказ: «useEffect выконваецца пасля атрыбутавання элемента. useLayoutEffect выконваецца перад тым, як браузер намалюе экран. Ожывайце useLayoutEffect, калі вам трэба змерыць структуру DOM.»
Болей адказ: разлік у часе ўвесь час ведаць, але самэ тое, чаму гэты час мае значэнне, і ўражае якісна адказ. useEffect выконваецца асінхрональна пасля таго, як браузер вже намалюе экран. useLayoutEffect, на адварот, выконваецца сінхрональна ведразу пасля таго, як React завершыў вычысленне змян у DOM, але перад тым, як браузер зможа намалюваць.
Гэты разлік значыць, што useLayoutEffect фактычна блакуе візуальную адначыну. Якщо вы пасадзіце трыцяжкія вычысленні ў яго, корыстнік пабачыць замарожаны экран. Самэ таму дакументацыя React рекамендуе выбіраць useEffect як стандарт — непатрэбна блокавання процеса малювання ўскладнілае працэс выконання коду.
Тым часам існуюць правамеркаваныя прычыны для викорыстання useLayoutEffect, кроме простага «вызначэння размера DOM». Адным з хорашых прыкладаў є запобежэнне видным меркацьвам. Уявіце сабе адрасную панель, якой положэнне залежыць ад размера цялевага элемента — выкананне такых расчыткаў пазіцыявання ўнутры useEffect вызывае видныя меркацьвы, калі адрасная панель на хвілі з’яўляецца не там, дзе трэба, перш чым апусціцца на правыя месцы. Выкананне тых сабоў расчыткаў унутры useLayoutEffect абэгаецца меркацьвам цалком, таму што гэта відбываецца раней, чым браузер намалюе ўсё.
У гэтай групе хуків існуе ўжо трэці, які багато разработчыкаў праігнораваюць: useInsertionEffect. Яго мета — дазволіць інструментам CSS-у-JS вставляць правіла стылю ў документ раней, чым механізмы раскладкі зможуць прачытаць застарэлую інформацію пра стыль з DOM. Большасць разработчыкаў ніколі не будзе ўпэўненая ў яго прымененні, але сама ж упэўненасць у тым, што ён ўскладнівае жыцёвы цикл эфектаў у React, свідчыць пра глэбокей разуменні таго, як React 18 адмаўляецца з працэю з эфектамі.
Інтэрв’юер можа запытаць, што будзе, як вы викорыстаеце useLayoutEffect пад час сервернай рэндарынацыі. Адказ: React паведаміць вас пра гэта, таму што на сервере няма DOM, які можна было б вымерыць. Хук проста не будзе выкананы пад час SSR, таму любая логіка, якая залежыць ад DOM, павінна або маты захист толькі для кліента, або быць перанесенаючы ў useEffect.
Запытанне 3: «Паспясціце працэю React у практыцы. Калі компонент пераранжуеяся?»
Проста адказ: «Компонент пераранжуеяся кожны раз, калі зменяецца яго стан або параметры.»
Болей даклэвая адказ: гэта толькі верхні слой проблемы. Што ўсё-такі ёсць значным як «змена», і што робіць React, калі ён яе выявляе — гэта болей цікава запытанне.
Компонент пераранжуеяся за трохі абставінакоў:
- Зменяецца яго саённы стан, зазвычай за дапамогою функціі для змены стану
- Пераранжуеяся яго родны компонент, незалежна ад таго, чыі змениліся параметры, якія ён отримаў
- Зменяецца значэнне контексту, якое ён викорыстоўвае
Ключовым моментам являецца другі пункт: React не пораўнюе пропсы перад тым, як вырашыць, чы рэендараваць дзецячы компонент. Як толькі рэендаруецца вышэйшы компонент, за прыродай яго дзецячыя компоненты таксама рэендаруюцца. Пораўненне пропсаў ёст канпютатываўскі зусилле, і ў большасці рэальных случаў дзецячы компонент у будзь-якім случае патрэбна адчыніць змены, таму прахіднае айскаленне гэтага пораўнення ёст разумным компрамісам.
Сяродзе гэтага развіцкавальнікі часта, і часам некоректна, вяртаюцца да React.memo. Сама мемоізацыя таксама караеся — React все рава павінен адбыць пораўненне пропсаў падчас кожнага рэендарування. Якщо гэтыя пропсы ёсць складнымі об’ектамі, або якщо сам компонент, які пакрываецца, і так лёгка рэендаруецца, тады його пакрыцце React.memo насправдзе можа пагоршыць працэсавую ефектыўнасць, а не падбіць яе.
Праўя майстэрнас крычыць у веданні таго, калі оптымізацыя даслівна неабходная. Корыстны прыем — утримвацца ад зберагання рэзультаатаў у памяці, пакуль не будзе зьвярстана рэальная проблема. Адначасова выкорыстоўваючы інструмент React DevTools Profiler, спачатку трэба знаходзіць справжнія вузкія месца, а толькі пасля чаго цэлевым спосабам застаўляць React.memo, useMemo чы useCallback. Неразумная оптымізацыя ў React зазвычай означае працю праз протыяднечнасьць з дзеяньмамі самай парадыгмы.
Функцыя адначасовага выканання у React 18 дадае ўсё большай складнасьці. Тепер процесы выканання можна перарываць, надаваць ім прыорітэты чы нават абрываць у паўпарадку. Розумець, што выкананне коду не завжды прыводзіць да сінхроннага зберагання данных у DOM, є абавязковым для стварэння коду, які правільна працуе ў умовах адначасовага выканання.
Запытак 4: Как следуе кераваць управленьнем станам у вялікай аплякацыі на React?
Слабая адаптация спрыгвае да гэтага як да пытанні пра інструменты: для всаго глобальнага вжываецца Redux, а для всаго локальнага — useState.
Болей адекватная адаптация спачатку выявляе, які тип стану ў кампаніі і хто на самай працо з яным, перш чым выбіраць якую-небудзь бібліятэку.
Стан у большай кампаніі зазвычай дзеліцца на чатыры групы:
- Локальны стан UI: значэнні форм, переключыкі, чы розкрываецца модальны вікн. Для гэтаго дапаможа
useState. - Стан сервера: даны, якія запрашваюцца з бэкенду. Для гэтаго створаны React Query чы SWR, адколі яны вже рашаюць проблемы кэшавання, усунення дублікаў, фоновага падтрымкання данных і оптымістычных апдэйтаў — функцый, якія ніколи не былі задуманы для Redux.
Шырока памылка — з самага пачатку проекту выбіраць Redux. Redux імпэратыўна падходзіць для сапраўдна складнай логікі на стороне кліента з множыцью взаімазалежных апдэйтаў, але большасць застосоў на самай працэ паставілены не ў такой стан — тое, што выглядае як стан кліента, часта ёсць проста стан сервера пад маскай. Зберагчы адпаведзі API ўнутры Redux, можна супорачыцца з тым, што гэта як викорыстоўваць молот для павішання карточкі: гэта можна зробіць, але для гэтага трэба набагато больш зусіль, чым тое выкананне вимагае.
Калі Redux дапаможыць справдзілася, хорашым падходам є яго адузеўка з Redux Toolkit і RTK Query. RTK Query берае на сябе адпаведальнасці за стан сервера, тады як Redux керуе толькі той часткай логіки кліента, якая сапраўды складная. Раздзелэнне гэтых аспектаў спакойвае загальную архітэктуру і яе легча разумець.
Раздзял 2: Глыбокі аналіз JavaScript
Запитанне 5: Паспяшыце закрыцці ў JavaScript. Дайце практычны прыклад.
Паверхневая адказка па закрыцце — гэта проста функцыя, яка зберагае зменныя з свайго абгорнуцькага прастора.
Глыбэйшая адказка связвае гэта з лексычным прасторам: калі ствараецца функцыя, яна захопляе кансэкты да зменных, якія знаходзяцца ў яе апошні, у тым моманті, і застаецца з можлівасцю да яных адчыніць нават пасля таго, как выконанне пераходзіць за межы таго перваснага прастора.
Тое, што выделяе хорашага кандыдата, — гэта ўмеласць паспяшаць, чаму гэтая прымета мае значэнне самэлькі ў React. Разглядзім модель, якая часта спрычыняе багі:
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
console.log(count); // Always logs 0
setCount(count + 1); // Resets to 1 every time
}, 1000);
}, []); // Empty deps = closure over initial count
}
count, які выкарыстоўваецца ў setInterval, застаецца на тым значэнні, якое існавало пад час першага атрыбутавання. Пакалі эфект выконваецца толькі адназначна, завялікі пустыя массив залежнасцей, гэты закрытый функцыяны ніколі не апошнаваецца новымі значэннямі. Проста дадаванне count у список залежнасцей таксама не ўсуне проблему, адтак як гэта будзе спрычыніць знеасабліванне і паўторную стварэння інтэрвалу пасля кожной змены. Правільны спосаб — выкарыстоўваць функцыональную форму апошнавання, setCount(c => c + 1), якая абоўсумова пазбегае выкарыстоўвання застарэлага закрытага функцыяна.
Закрыцці таксама вызываюць супершчэпленні з абёрбатарамі запуску падзеяў у спецыяльных хукі. Калі абёрбатар прыўязуецца ўнутры useEffect і чытае данні з статаусу, у гэтым працюе закрыцце. Частая тактіка для хука у стылі useEventListener — зберагчы функцію-обрабоўчык унутры ref, так ён зможа завжды чытаць найсвежэйшую версію даных без патрэбы ў новай прыўязцы.
Нічога з гэтага не значыць, што закрыцці трэба аўтаматычна ухілявацца — яны ёсу ключовым механізам, які варта опанаваць. Шаблоны модуляў, прыватныя зменнікі, функцыі-фабрыкі і курріюванне — усе гэта завісяць ад яных. Важлівым навыкам є точна ведаць, калі ствараецца закрыцце, і пераканацца, што ён захопляе самэ тое значэнне, якое насправды патрэбна.
Запитанне 6: Чым ёсць цыкл падзеяў? Паспяшыце мікро- і макратаскі.
Паверхневая адказка згадвае, што цікл задач караць на асінхронную роботу, і што мікразвядкі выкананы раней за макразвядкі.
Более детальная адказка поясняе, што JavaScript выкананы на аднай нітке, а браузер сімулюе канкурэнцыю за дапамою ціклу задач. Сінхронны код выкананы на стаке вызоў; калі з’являецца асінхронная операцыя, яна перадаецца Web API — setTimeout, fetch, DOM-задачам — і калі гэта робота завершыцца, яе калбэк кладзецца ў чергу.
Важным моментам, які варта адзначыць, ёсь тое, што існуе не адна лишняя черга. Макрозадачы — setTimeout, setInterval, операцыі I/O — падаюць у адну чергу, тады як мікрозадачы — Promise.then, queueMicrotask, MutationObserver — у іншую. Калі стак апыланняў стае порожнім, цыкл адбывання падзеяў спачатку апрацоўвае всю мікрозадачную чергу, прычым не апрацоўваючы нават аднай макрозадачы.
Это стварае рэальную небяпеку: мікрозадачы можаць «зголадзіць» рэшту программы. Якщо новыя мікрозадачы продовжаюць дагружацца ў чергу рэкурсыўна, задачы, запланаваныя за дапамогай setTimeout, ніколі не павярнуцца да апрацоўкі. Такая ситуацыя можа заморозіць інтерфейс, калі Promises адна за другой выкананыя ў цыкле, не вяртаючы керуванне назад браузэру.
Это безпасэчна з’яўляеся з тым, як React групавае абновяванні статаусу. У React 18 абновяванні статаусу групаваюцца автаматычна, незалежна ад таго, дзе яны выкананы — унутрь setTimeout, унутрь Promise чы ўнутрь натыўнага обрабнавача змян. Раней, да React 18, абновяванні, якія выкананы унутрь setTimeout, працавалі по аднаму, а не былі групаваны. Розумеўшы цикл змян, можна зрозумець, чаму автаматычная групаваеўка у React 18 ёсць важлівай: яна паў’язуецца з очаквальнай чергай мікраскарабоў, так што всі чакаючыя абновяванні выкананыя разам перад наступным атрыбутаваннем.
Вас таксама можа папросіць спрогназаваць выход такога короткага фрагмента:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
Апэктыўны адказ: 1, 4, 3, 2 — сінхронныя запаведзі выкананыя першыя, пасля чаго — мікраскарабы, такія як калбэк Promise, а толькі пасля чаго выкананы макраскараб, запісанный у setTimeout.
Запытанне 7: «Паспясці this у JavaScript. Якое ў яго разлічнае адзінства ад іншых мов?»
Слабыя адказ: «this паказывае на той об’ект, які вызваў функцыю».
Адказ з деталямі: «У JavaScript this прыкладзваецца за дапамою дынамічнага скоупінгу, а не лексычнага. У большасці мовы значэнне self або this фіксуецца ў момент адзначэння функцыі. У JavaScript жа яго значэнне выклікаецца пад час вызову, на аднойчынку з тым, як функцыя вызываецца, а не з тым, дзе яна знаходзіцца ў коде».
«Існуе чатыро правіла прыкладзвання з прапорцямі прываліднасці:
- Новае прыкладзванне:
new Foo()ставіцьthisна ўсходзячую інстанцыю - Явнае прыкладзванне:
foo.call(obj),foo.apply(obj)абоfoo.bind(obj)прымушваюцьthisстаць об’ектам, які вы пасылаете
obj.foo() прыводзіць да таго, што this стае роўным objfoo() заставляе this быць undefined у режыме strict mode, а інакша вяртаеся да globalThis"Функцыі-стрэлкі навмесна нарушаюць гэты патерн — яны успадковуюць this лексычна з таго простору імен, які ўсёляўае іх. Самэ гэтая прычына змусіла разработчыкаў вжываць функцыі-стрэлкі ў класовых компонентах React пры тым, калі яшчо не існавала хуків: такім чынам яны ухіляліся ад неабходнасці вызываць .bind(this) унутры канстрактара."
"Код у React, які выкарыстоўвае хукі, рэдка калі безпосередна выкарыстоўвае this, адколі компаненты больш не ў формате класаў. Тым не менш, гэта панявленне з’яўляецца, калі вы адтульватэ разрабатаныя класовыя компаненты, інтэгруеце бібліятекі трохоўшых сторонніх разработчыкаў, або сталкнуліся з кандыдатам на працу, які хоча праконтролаваць вашы знанні фундаментальных прынцыпаў JavaScript. Частая падступка ў рэальных умовах — перадача методу об’екта як калебэка: напрыклад, передача obj.handleClick да аберанта змагання, што пазбавляе яго неявнай прыўязкі і заставляе this абсырвацца на неспадзеваным об’екте."
Запитанне 8: "Што такое JavaScript Promises? Паспяшыце асінхроннае/await-апэлуванне."
Слабыя адказы: "Promises керуюць асінхронной роботай, а async/await — гэта проста синтаксічны элемент на ўзбочцы яных."
Серьжоўны адказ: «Прамеса — это значэнне, якое ўсё еще не існуе, але зрэшты будзе задаўана. Яна заменяе заплутаныя ланцюгі калбэк-функцый на інтерфейс, які можна складаць, і адносны спосаб прызначэння успеху чы розбіяння».
«Тое, што робіць прамесы справаўдзіва корыстнымі, — не синтаксіс, а гаранціі, якія стояць за імі. Калі прамеса задаўаецца — чы то выпанавалася, чы адхоўвалася — гэты результат стае незменным і не можа змяніцца. Самэ гэта незменнасць робіць іх можлівымі да складання і прыемнымі для аналізу».
«Называць async/await ‘толькі сахаром’ — значыць недаце ўсёго значэння: яны фундаментальна пераформатаваюць спосаб напісання асінхронной логікі, дазваляючы яй чытацца як сінхронны код і робячы ёё набагато простэйшай для разумення. Аднак яны таксама ствараюць калькі, на якія варта звернуць увагу».
// This runs sequentially - 6 seconds total
async function sequential() {
const a = await fetch('/a'); // 3s
const b = await fetch('/b'); // 3s
}
// This runs in parallel - 3 seconds total
async function parallel() {
const [a, b] = await Promise.all([fetch('/a'), fetch('/b')]);
}
"Адзін з частых грэшакоў сярод менее апытных разработчыкаў — это размешчэнне await усереды ціклу, што нехтаю прыводзіць да таго, што аперацыі выкананыя ў спадарожнечу, а не паралельна. Рашэння — выкарыстоўваць Promise.all, калі аперацыі не залежаць адзіна ад другога, а цікл for...of з await застаўляць у тых случаях, калі патрэбна строгая последоўнасць."
"Карэнтаванне адзіяў — ўсё тое ж месца, дзе выходзяць на чырвоныя сігналы. Абгортаванне вызову await у try/catch дапамагае пазначыць адмову, але якщо гэтага абгортавання не будзе, некарэнтаваная адмова можа прычыніць зупінку процэсу Node.js. У фронтэндзе абгортаванне асінхронных вызоваў у межы карэнтавання адзіяў або выкарыстоўванне бібліятэкі, такой як React Query, якая декларатыўна керуе станамі адзіяў, дапамагаюць ухіліцца ад такога спосабу выходу на чырвоныя сігналы."
Раздзел 3: Дыяграматыка системы і архітэктура
Запытанне 9: «Адзінаковаце дыяграматыку рэальна-часовага саўместнага рэдагувальніка дакумента, падобнага да Google Docs.»
Этае запытанне цэлком зменяе акцэнт у спытванні. Спытач больш не дапытваецца пра вашы знанні пра React — ён хочаць пабачыць, як вы разумеете архітэктуру системы.
Надзеяны падход выглядае так:
«Перш чым напісаць хоць адну лінію коду, я бы чыткая визначыў трэбованні:
- Сколькі людзей рэдагуе адночасова? Дыяграматыка для 10 адночасовых корыстнікаў зусім не падобнае да дыяграматыкі для 10 000.
- Якая затрымка ўзьямаецца за прыемную — справжні рэальны час, ці што-сабой ближэй да майже рэальнага часу?
- Чы трэба, каб прыстанок работаў без інтэрнету?
- Якую стратэгію рашэння канфліктав прымем мы?»
«На фронтэндзе:
- Управленьне станам: кожны кліент зберагае свой локальны копію дакумента. Змены спачатку застосоўваюцца на кліянцы оптымістична, а пасля выкладзяюцца на сервер, який перадае іх усім іншым падключаным кліентам.
- Опэрацыйная трансформацыя або CRDT-ы: гэты механізм служыць для рашэння суперсечаючыхся змян. OT была первачайшая тэхніка Google, але яна залежыць ад центральнага сервера для вырабаткі рашэння па порядку. CRDT-ы (Conflict-free Replicated Data Types) могу працаваць па принцыпе peer-to-peer, а інструменты на кшталт Yjs робяць іх все бол популярнымі.
requestAnimationFrame, а таксама дэбаусуецца выходзячы сінхронізацыйны запит, тады як не выкананыя запыты за кожны нажым клавішы."У слою сінхронізацыі:
- WebSocket адпавядае за транспорт у рэальны час
- Server-Sent Events або дзействы працягванага польсавання выступаюць як альтэратыва, якщо не ўдаецца стварыць з’ўязак WebSocket
"Сапраўдна складная частка гэтай проблемы не мае нічынага з рэндарованнем у React — гэта модель адпаведнасці, якая стоіць за ёю. Калі два чалавекі пішчуюць у абсолютна той самы пункт курсора ў той жа момент, што должна стацься? Адказ цэлкам залежыць ад таго, чы вы выбралі OT чы CRDTs, і гэтае адно рашэнне вплывае на майже кожны іншы архітэктурны выбор, який следуе."
Запытанне 10: "Як оптымізаваць застосунак React, які медленна завантажаецца і з яким важка взаімадзейваць?"
Незначны адказ: перыяктуванне набору тактыкаў — мемаізацыя, лэзі-лаудынг, раздзеленне пакетаў — без жадного контексту.
Адказ, які выдзеляецца: «Спачатку трэба вимерываць, а не здагадваліцца. React DevTools Profiler і панель Performance у Chrome DevTools паказваюць, чый галоўны бар’ер — час завантажэння, час адрасавання інфармацыі чы то і тое разам — і няма сэнсу оптымізаваць слепа».
Щодо завантажэння:
- Раздзеленне коду: Раздзеленне на адпаведныя маршруты за дапамою React.lazy і Suspense — гэта базовая практыка, але на гэтам ёй не трэба зупініцца. Важкія компоненты, якія не відразу видны — модалы, контэнт пад основным фонам — таксама заслуговуюць на своія точкі раздзелення.
- Пазылковае завантажэнне: Ўжывайце
<link rel="preload">для критычна важлівых ресурсоў, а таксама поўяжыце React.lazy з функціяй пазылковага завантажэння для маршрутаў, якія корыстувач, верагодна, адвідае далей.
import lodash from 'lodash' заместо import debounce from 'lodash/debounce' можа прыняць значэнне 100 КБ у падсумковым розмере пакета.Што стосуецца взаімадзеяў:
- Віртуалізацыя: Калі колькасць элементаў у лісте перакрочыць прыблізна 50, выкорыстоўваеце react-window або react-virtualized. Адрасаванне 10 000 элементаў DOM адразу ніколі не будзе быстрым, незалежна ад таго, насколькі эфектыўны ўсё рэшта вашага коду.
- Дысціплінованая стратэгія мемаўвання: спачатку аналізуйце, потым дзейнічайце. Абгортавайце дарогія вычысленні за дапамою
useMemo, дарогія калебакы за дапамоюuseCallback, а компаненты, якія зайва раз перарэндруюцца, — за дапамоюReact.memo. Мемаўванне всага за замовчаннем, без ацэнкі рэальнага падтачку, зазвычай даўае дапамогу больш у вачох накладных расходаў, чым ўсуне іх. - Размешчэнне статаусу: Храніце статаус як магчыма ближэй да компанента, який яго фактычна выкарыстоўвае. Перанесенне статаусу да спакойнага предка толькі таму, што гэта выглядае апрантней, вызывае дадатковыя перарэндры ў кожны раз, калі статаус зміняецца.
- Раздзелэнне контэкстаў: Калі адны контэкст сумешчае высокачастотныя апдэйты — напрыклад, пазіцыю мышы — з низкачастотнымі — напрыклад, статус автанацыі — раздзеліце яго на два. Інакш кожны рух мышы вымагае перарэндру кожнага корыстувальця, нават тых, якімыя значыць толькі аптанацыя.
Па асэнцеі спрытнасці:
- Экраны-скелеты заместо індыкатора загрузкі даюць вражанне, што інтэрфейс працюе быстрей, адколі контент практычна поступова запоўняеся, а не з’являецца заодно.
- Поступовая загрузка з выкарыстоўваннем механізма
Suspenseу React 18 дазволяе спачатку загрузіць важлівы контент, а второсортныя часткі — пазней. - Варта стежыць за показніком Interaction to Next Paint, новейшым паказніку Core Web Vital ад Google. Ён заменяе First Input Delay, тым што фіксуе рэакцыйнасць на всю трываласць жыццёвага циклу стораніцы, а не толькі пасля першай інтеракцыі. Цэль — кантролюваць час выконання обрабоўчыкаў запускоў у межах 200 мілісекунд.
Спадні матэрыялы
- Адміністратыўная архітэктура: проблемы, якія ствараюць труднасці для команд, якія прыоритэтаваюць фронтэнд у React — Інструкцыя па пяці распалохах у дизайне адміністратыўной часткі, якія часта з’являюцца ў проектах на React — ад неправильнага викорыстоўвання парадыгмы API да нестабільных розгортанняў — а таксама патрэбныя архітэктурныя рашэння для забезпечэння надзеі на працэс у рэальных умовах.
- Работа з станамі інтэрфейсу ў рэальных умовах за дапамой умовнага атрыбута React — Навучыцеся ствараць інтэрфейсы для аутантыкацыі, ролей, прав, стану завантажэння, памилак і порожніх станоў у React за дапамой практычных шаблонаў умовнага атрыбута.