2-юми феврали соли 2017 Энн Тейлор мақолаи 12 Things We Need to See From WordPress Page Builders in 2017 + Who Already Gets It Right-ро дар CodeInWP навишт. Мо зиёда аз як сол инҷониб Page Builder Sandwich-ро пайваста такмил медиҳем: мо таҳқиқ мекунем, ба муштариёнамон гӯш медиҳем, бинобар ин фикр мекардем, ки Page Builder Sandwich ба мақолаи «Кӣ онро дуруст иҷро кардааст»-и CodeInWP дохил мешавад. Аммо ба далели маҳсулнокӣ (суръати кор) ворид нашудем.
Аз ин рӯ, мо аз Энн дар ин бора пурсидем ва ӯ посух дод:
…Ман бо нусхаи ройгон каме кор кардам. Он хеле умедбахш ба назар мерасад: модулҳои зиёд, интерфейси хеле фаҳмо, таҷрибаи олии WYSIWYG, ҳама чиз ба осонӣ кашола карда мешавад. Аммо, вақте ки ман дар саҳифа тақрибан 10 модул доштам, бинобар суръати пасти таҳрир идома додани кор бо он душвор шуд…
Ҳамин тавр, ба гуфтаи ӯ, Page Builder Sandwich мушкилоти маҳсулнокӣ дорад. Ва азбаски мо ҳамеша ба фикру мулоҳизаҳо гӯш медиҳем, мо инро тафтиш кардем.
Санҷиши маҳсулнокӣ
Барои санҷидани маҳсулнокии PBS ба мо роҳе лозим буд; азбаски PBS асосан дар браузер тавассути Javascript кор мекунад, профайлери Timeline-и Chrome воситаи муносиб барои ин кор буд. Профайлери Timeline метавонад муайян ва чен кунад, ки кадом равандҳо дар саҳифаи веб ҳангоми иҷрошавӣ ба амал меоянд, ки ин барои ёфтани нуқтаҳои заифи суръат комилан мувофиқ аст.
Мо қарор додем, ки аввал содатарин қадамҳоро санҷем – ҳаракат додани муш дар байни якчанд унсурҳо ва сатрҳо. Осон аст, дуруст? Мо боварӣ доштем, ки бо як чизи оддие мисли ин ба мушкилоти маҳсулнокӣ дучор намешавем. Мутаассифона, мо хато кардем.
Вақте ки мо тугмаи сабтро пахш кардем, мушро тақрибан 2 сония дар экран ҳаракат додем ва сипас тугмаи қатъро пахш кардем. Ин аст ҷадвали вақти ҳосилшуда аз профайлер:
Ана халос! Он пур аз монеаҳои маҳсулнокӣ мебошад!
Дар график ҳодисаҳои зиёде рух медиҳанд, аммо мушкили равшантарин ин аст, ки дар он майдонҳои бунафшранги зиёде мавҷуданд (ки набояд чунин мебуд). Илова бар ин, ин минтақаҳои бунафш ба таври назаррас хеле васеъ мебошанд ва ҳама ба авҷи график мерасанд. Шумо инчунин пай хоҳед бурд, ки график низ ҳамеша пур аст ва майдонҳои бунафшранг қариб ҳеҷ гоҳ ба сифр намерасанд. Чунин ба назар мерасад, ки браузер ҳамеша бо коре машғул аст ва қариб ҳеҷ гоҳ истироҳат намекунад.
Аммо ҳамаи ин минтақаҳои бунафшранг аслан чӣ маъно доранд?
Профайлер ба мо нишон дод, ки онҳо reflows номида мешаванд. Ин аст таърифи он, ки reflow чист аз сомонаи Google Developer:
Reflow номи раванди браузери веб барои аз нав ҳисоб кардани мавқеъҳо ва геометрияи унсурҳо дар ҳуҷҷат мебошад.. reflow амалиёти бандкунандаи корбар (user-blocking) дар браузер мебошад.
Пас, ин маънои онро дорад, ки ҳаракат додани муш дар PBS боиси миқдори зиёди reflow-ҳо мегардад. Бадтараш он аст, ки ҳар як reflow браузерро лаҳзае бозмедорад, то ҳисобкуниҳои худро ба анҷом расонад. Reflow-ҳои бештар маънои таваққуфҳои бештари браузерро доранд ва таҷрибаи кор боз ҳам бештар ноҳамвор (janky) мешавад. Ба забони соддатар, бисёр будани минтақаҳои бунафш = бад.
Ҳамин тавр, маълум шуд, ки Энн ҳақ буд: мо воқеан як мушкили бузурги маҳсулнокӣ дорем, аз ин рӯ дастаи мо фавран ба кор пардохт, то онро зуд ислоҳ кунад.
Ислоҳи мушкили Reflow / Jank-и мо
Пеш аз ҳама, ба мо лозим омад, ки каме таҳқиқ кунем, то бифаҳмем, ки дар навбати аввал чӣ боиси ин reflow мешавад. Мо фаҳмидем, ки зоҳиран бисёр чизҳои маъмул дар Javascript метавонанд браузерро ба анҷоми reflow водор кунанд.
Қариб ҳар як функсияе, ки шумо метавонед барои гирифтани паҳнӣ, баландӣ ё мавқеи унсури DOM истифода баред, метавонад reflow-ро ба вуҷуд орад. Пол Айриш рӯйхати васеи ҳамаи хосиятҳо ва функсияҳоро дар Javascript, ки метавонанд ин корро кунанд, навиштааст. Хабари бад ин аст, ки Page Builder Sandwich бисёре аз ин хосиятҳо ва функсияҳоро истифода мебарад, ки ҳамаи онҳо боиси reflow мешаванд:
- elem.getBoundingClientRect()
- window.getComputedStyle()
- window.scrollY
- ва бисёр чизҳои дигар…
Ислоҳи №1: Кэшкунии равандҳои гаронарзиши Reflow
Роҳи равшантарин ин аст, ки он хосиятҳо ва функсияҳо истифода БУРДА НАШАВАНД. Аммо, PBS ба онҳо сахт такя мекунад ва мо бе онҳо кор карда наметавонем.
Роҳи ҳалле, ки барои мо боқӣ монд, кам кардани шумораи даъватҳо ба ин функсияҳо то ҳадди имкон буд. Қисми душвор дар ин ҷо он буд, ки мо ин хосиятҳо ва функсияҳоро борҳо дар қисмҳои гуногуни PBS истифода мебурдем ва аксари вақт мо онҳоро барои як унсури DOM якчанд маротиба татбиқ мекардем. Барои ислоҳи ин, мо механизми кэшкунии худро барои ҳар як хосият/функсияи мушкилсоз эҷод кардем.
Масалан, функсияи getBoundingClientRect ба мо андозаҳои ҷории пикселии боло, чап, паҳнӣ, баландӣ, рост ва поёни унсури DOM-ро медиҳад. Мо ин функсияро ҳамеша барои ҳисоб кардани маконе истифода мебарем, ки контурҳои унсурҳо дар PBS кашида мешаванд. Ин аст функсияи кэшкунӣ, ки мо барои ин сохтем:
// Cache: Our client rects are kept here, we can use this to clear them later.
var elemsWithBoundingRects = [];
window.pbsGetBoundingClientRect = function( element ) {
// Check if we already got the client rect before.
if ( ! element._boundingClientRect ) {
// If not, get it then store it for future use.
element._boundingClientRect = element.getBoundingClientRect();
elemsWithBoundingRects.push( element );
}
return element._boundingClientRect;
};
Ба ҷои даъват кардани getBoundingClientRect, мо акнун pbsGetBoundingClientRect-ро истифода бурдем. Акнун ҳар дафъае, ки client rect дархост карда мешавад, мо он арзишро барои муроҷиати оянда нигоҳ медорем ва ба ин васила шумораи ангезаҳои reflow-ро маҳдуд мекунем.
Мо инчунин ба роҳе ниёз доштем, то ҳангоми беэътибор шудани client rect-ҳои захирашуда кэшро тоза кунем. Арзишҳои client rect-и захирашуда ҳангоми чарх задани саҳифа аз ҷониби корбар ё илова/тағйир/нест кардани унсурҳо дар экран тағйир меёбанд. Аз ин рӯ, мо функсияи тозакунии кэшро сохтем, ки метавонем онро ҳар вақте ки ба арзишҳои тозаи client rect ниёз дорем, даъват кунем:
var clearClientRects = function() {
var i;
for ( i = 0; i < elemsWithBoundingRects.length; i++ ) {
if ( elemsWithBoundingRects[ i ] ) {
elemsWithBoundingRects[ i ]._boundingClientRect = null;
}
}
elemsWithBoundingRects = [];
};
Мо инчунин ин механизми кэшкуниро барои дигар даъватҳои функсияҳои гаронарзиш, ки одатан истифода мебарем, татбиқ намудем.
Ислоҳи №2: Гурӯҳбандии якҷояи хонишҳо ва навиштҳо бо истифода аз FastDom
Татбиқи ислоҳи №1 маҳсулнокии PBS-ро зиёд кард, аммо ин кофӣ набуд.
Каме бештар дар Google ҷустуҷӯ карда, мо ба мақолаи Уилсон Пейҷ дар бораи пешгирии «layout thrashing» дучор шудем. Уилсон мегӯяд:
Layout Thrashing (reflow) вақте рух медиҳад, ки JavaScript якчанд маротиба пайиҳам ба DOM менависад ва сипас аз он мехонад ва боиси reflow-ҳои ҳуҷҷат мегардад.
Зоҳиран, маҳдуд кардани даъватҳои шумо ба хосиятҳо ва функсияҳои мушаххаси reflow-барангез кофӣ нест. Вақте ки шумо дар DOM якчанд «хониш» ва «навишт»-и пайиҳамро иҷро мекунед, ин ҳам боиси reflow-и браузер мегардад. Ин аст як сенарияи маъмулӣ мустақиман аз сомонаи Уилсон:
// Read var h1 = element1.clientHeight; // Write (invalidates layout) element1.style.height = (h1 * 2) + 'px'; // Read (triggers reflow) var h2 = element2.clientHeight; // Write (invalidates layout) element2.style.height = (h2 * 2) + 'px'; // Read (triggers reflow) var h3 = element3.clientHeight; // Write (invalidates layout) element3.style.height = (h3 * 2) + 'px'; // Document reflows at end of frame
Мисоли дар боло овардашуда 3 reflow-ро ба вуҷуд меорад, зеро андозаҳои тамоми саҳифа пас аз навиштан беэътибор мешаванд. Ислоҳи пешниҳодшуда барои ин аз нав ташкил кардани код мебошад, то ҳамаи хонишҳо ва навиштҳо якҷоя гурӯҳбандӣ шаванд ва тамоми раванд танҳо 1 reflow-и браузерро ба вуҷуд орад:
// Read var h1 = element1.clientHeight; var h2 = element2.clientHeight; var h3 = element3.clientHeight; // Write (invalidates layout) element1.style.height = (h1 * 2) + 'px'; element2.style.height = (h2 * 2) + 'px'; element3.style.height = (h3 * 2) + 'px'; // Document reflows at end of frame
Порчаи коди боло ислоҳи мушкилотро осон нишон медиҳад. Аммо дар асл, дар PBS хондан ва навиштани чизҳои reflow-барангез дар бисёр ҷойҳои гуногун ва дар замонҳои гуногун дар давоми давраи ҳаёти PBS рух медиҳад. Аз нав ташкил кардани ҳазорҳо сатрҳои коди Javascript ғайриимкон аст.
Хушбахтона, Уилсон инчунин дар мақолаи худ роҳи ҳаллеро пешниҳод кард. Вай скрипти хурди ёрирасонеро барои кӯмак ба якҷоя кардани ин хонишҳо ва навиштҳо бо номи FastDom сохтааст.
Ин аст баъзе кодҳо аз Page Builder Sandwich, ки FastDom-ро истифода мебарад ва инчунин Ислоҳи №1-и моро дар бар мегирад:
// Bunch together the reads from other threads.
fastdom.measure( function() {
// Use our cached client rect.
var rect = window.pbsGetBoundingClientRect( elem );
// Bunch together the writes from other threads.
fastdom.mutate( function() {
elem.style.top = ( rect.top + window.pbsScrollY() ) + 'px';
elem.style.height = rect.height + 'px';
elem.style.left = rect.left + 'px';
elem.style.width = rect.width + 'px';
}.bind( this ) );
}.bind( this ) );
Он чизе, ки FastDom мекунад, ин аст, ки ҳамаи даъватҳои fastdom.measure ва ҳамаи даъватҳои fastdom.mutate-ро якҷоя гурӯҳбандӣ мекунад ва онҳоро ба таври асинхронӣ иҷро менамояд ва ба таври муассир ҳамаи хонишҳо ва навиштҳоро барои коҳиш додани reflow-ҳо дар браузер муттаҳид месозад.
Ислоҳи №3: Дастрасӣ ба объектҳои услуб (Style Objects) гаронарзиш аст
Мо инчунин бо ёрии jsPerf муайян кардем, ки баъзе функсияҳои гирифтани услуб назар ба дигарон тезтар кор мекунанд.
Дар PBS ба мо одатан лозим меояд, ки арзиши ҷории услуби муайяни унсурро ба даст орем. Масалан, мо одатан барои гирифтани ҳошияи болоӣ (top margin) инро истифода мебарем:
var styles = window.getComputedStyle( elem ); var marginTop = styles.marginTop;
Аммо мо фаҳмидем, ки иҷрои ин кор хеле тезтар аст:
var marginTop = elem.style.marginTop;
Бо вуҷуди ин, elem.style.marginTop ва getComputedStyle хеле фарқ мекунанд. Якумаш ба мо танҳо услуби inline-и унсурро медиҳад ва ягон ҷадвали услубҳоро (stylesheets) ба назар намегирад; ва дуюмаш ҳам услубҳои inline ва ҳам ҷадвалҳои услубҳоро ба назар мегирад.
Зиёда аз ин, ҳатто вақте ки натиҷаи getComputedStyle кэш шуда буд, он ҳанӯз ҳам воқеан суст буд. Тавре маълум шуд, дастрасӣ ба худи объекти услуб раванди суст аст.
Хушбахтона барои мо, PBS ба унсурҳо услубҳои inline илова мекунад ва азбаски услубҳои inline (аксари вақт) нисбат ба ҷадвалҳои услубҳо афзалият доранд, ҳолатҳое мешаванд, ки гирифтани арзиши услуби inline кофӣ хоҳад буд. Пас агар мо ду усули болоро якҷоя кунем, метавонем кодеро эҷод кунем, ки хеле тезтар кор мекунад:
var marginTop = elem.style.marginTop;
if ( ! marginTop ) {
var styles = window.getComputedStyle( elem );
marginTop = styles.marginTop;
}
Натиҷаҳои такмили код
3 ислоҳи болоии мо таҳқиқот, санҷиш ва татбиқи амалии зиёдеро талаб карданд (ва баровардани хусусияти шрифтҳои моро ба таъхир андохтанд), аммо дар охир ҳамаи ин арзиши худро дошт.
Бозгашт ба санҷиши аввалияи мо оид ба ҳаракат додани муш дар экран барои 2 сония. Ин аст ҷадвали вақти кӯҳнаи ноҳамвор/кашолкорона:
Ва ин аст, ки ҷадвали вақти нави мо пас аз беҳтар кардани маҳсулнокӣ чӣ гуна ба назар мерасад:
Тавре мебинед, дар график қисмҳои бунафшранг камтаранд. Ва дар миқдори равандҳое, ки аз ҷониби браузер иҷро мешаванд, тафовути назаррас мавҷуд аст. Қисмҳои росткунҷа дар поён низ бориктаранд, ки маънои нисбат ба пештара тезтар иҷро шудани равандҳоро дорад.
Агар шумо миқдори майдонҳои бунафши баланд/васеъро дар графикҳои кӯҳна ва нав муқоиса кунед, мо шоҳиди 200% афзоиши аҷиби маҳсулнокӣ ҳастем! Мо инчунин афзоиши маҳсулнокиро дар ҳама самтҳо мебинем. Ҳамагӣ бад нест!
Хулосаҳо ва сабақҳо
Рости гап, пеш аз он ки Энн ин масъаларо ба миён гузорад, мо фикр намекардем, ки PBS мушкилоти маҳсулнокӣ дорад. Асосан аз он сабаб, ки мо компютерҳои пурқудрати таҳиягаронро истифода мебурдем ва нуқтаҳои заифи суръат он қадар ба назар намерасиданд. Ба гузашта назар афканда, санҷиши маҳсулнокӣ бояд яке аз авлавиятҳои асосӣ мебуд. Аммо ҳадди аққал ҳоло, аз версияи 4.3 сар карда, ин масъала ҳал шудааст.
Барои онҳое, ки мехоҳанд маҳсулнокии плагини WordPress-и худро беҳтар кунанд, махсусан агар шумо Javascript-и вазнинро истифода баред, инҳо хулосаҳои ман аз ин таҷриба мебошанд:
- Даъватҳои худро ба хосиятҳо/функсияҳое, ки боиси reflow мешаванд, маҳдуд/кэш кунед. Инро ҳамчун дастур истифода баред: What forces layout/reflow. The comprehensive list.
- «Хонишҳо» ва «навиштҳо»-ро ба услубҳои DOM якҷоя гурӯҳбандӣ кунед. Барои ин корро барои шумо анҷом додан аз FastDom истифода баред.
- Профайлери Timeline-и Chrome-ро истифода баред ва боварӣ ҳосил кунед, ки шумо ҳадди аққал reflow-ҳо (қисмҳои бунафш)-ро доред.