Jinsi Tulivyoongeza Utendaji wa Plugin Yetu kwa 200%

Imeandikwa na

katika

,

Mnamo Februari 2, 2017 iliyopita, Ann Taylor aliandika makala Mambo 12 Tunayohitaji Kuona Kutoka kwa Wajenzi wa Kurasa za WordPress Mnamo 2017 + Nani Ambaye Tayari Anafanya Vizuri katika CodeInWP. Tumekuwa tukiiboresha Page Builder Sandwich mfululizo kwa zaidi ya mwaka mmoja sasa: tunafanya utafiti wetu, tunasikiliza wateja wetu, kwa hivyo tulidhani Page Builder Sandwich ingeingia kwenye makala ya CodeInWP ya “Nani Aliyeifanya kwa Usahihi”. Hata hivyo, hatukuingia kwa sababu ya utendaji. ?

Kwa hivyo tulimuuliza Ann kuhusu hilo, naye akajibu:

…Nilijaribu toleo la bure kidogo. Inaonyesha matumaini makubwa: moduli nyingi, UI rahisi kueleweka, uzoefu mzuri wa WYSIWYG, kila kitu kinavutwa kwa urahisi. Hata hivyo, nilipokuwa na moduli kama 10 kwenye ukurasa, ikawa vigumu kuendelea kufanya kazi nayo kwa sababu ya kasi ndogo ya uhariri…

Kwa hivyo kulingana naye, Page Builder Sandwich ina matatizo ya utendaji. Na kwa kuwa huwa tunasikiliza maoni kila wakati, tuliichunguza.

Kupima Utendaji

Tulihitaji njia ya kuangalia utendaji wa PBS; kwa kuwa PBS huendeshwa zaidi kwenye kivinjari kupitia Javascript, Chrome Timeline profiler ilikuwa zana sahihi kwa kazi hiyo. Timeline profiler inaweza kutambua na kupima ni michakato gani inayofanyika kwenye ukurasa wa wavuti wakati unaendeshwa, ambayo ni bora kwa kupata vikwazo vya kasi.

Tuliona tunapaswa kwanza kupima hatua rahisi zaidi – kusogeza kipanya chetu kwenye vipengele na safu mlalo nyingi. Rahisi, sivyo? Tulikuwa na uhakika kwamba hatungekumbana na matatizo ya utendaji kwa jambo rahisi kama hili. Kwa bahati mbaya, tulikosea.

Mara tu tulipobonyeza kitufe cha kurekodi, tulisogeza kipanya kwa takriban sekunde 2 kwenye skrini, kisha tukabonyeza kitufe cha kusimamisha.  Hapa kuna ratiba ya matukio iliyotokana na profiler:

Tazama na uone! Imejaa tele vikwazo vya utendaji!

Kuna mambo mengi yanayotokea kwenye grafu, lakini suala lililo wazi zaidi ni kwamba kuna maeneo mengi ya zambarau ndani yake (ambayo haikupaswa kuwa hivyo). Zaidi ya hayo, maeneo haya ya zambarau yanaonekana kuwa mapana sana, na yote yanaonekana kufikia kilele cha grafu. Pia utagundua kuwa grafu imejaa wakati wote pia, na kwamba maeneo ya zambarau karibu kamwe hayashuki hadi sifuri. Inaonekana kama kivinjari huwa na shughuli nyingi kila wakati kikifanya kitu, na karibu hakipumziki kamwe.

Lakini maeneo hayo yote ya zambarau yana maana gani hasa?

Profiler ilikuwa nzuri kiasi cha kutuambia kuwa yanaitwa reflows. Hii hapa ni fasili ya reflow ni nini kutoka kwa tovuti ya Google Developer:

Reflow ni jina la mchakato wa kivinjari cha wavuti wa kukokotoa upya nafasi na jiometri za vipengele kwenye waraka.. reflow ni operesheni inayomzuia mtumiaji katika kivinjari.

Kwa hivyo hii inamaanisha kuwa kusogeza kipanya chako kwenye PBS huchochea idadi kubwa sana ya reflows. Kilicho kibaya zaidi ni kwamba kila reflow husimamisha kivinjari kwa muda ili kiweze kumaliza kufanya hesabu zake. Reflows zaidi zinamaanisha vituo vingi vya kivinjari, na utumiaji unakuwa hata wenye kugugumia (janky) zaidi. Kwa maneno rahisi, maeneo mengi ya zambarau = mbaya.

Kwa hivyo ikabainika kuwa Ann alikuwa sahihi: tuna kikwazo kikubwa cha utendaji, kwa hivyo timu yetu ilianza kazi mara moja kurekebisha mara moja.

Kutatua Tatizo Letu la Reflow / Jank

Kabla ya kitu kingine chochote, tulihitaji kufanya utafiti ili kubaini ni nini hasa husababisha reflow hii hapo kwanza. Tuligundua kuwa inaonekana, mambo mengi ya kawaida katika Javascript yanaweza kukichochea kivinjari kusababisha reflow.

Takriban kitendakazi chochote unachoweza kutumia kupata upana, urefu au nafasi ya kipengele cha DOM kinaweza kuchochea reflow. Paul Irish aliandika orodha ndefu ya sifa na vitendakazi vyote katika Javascript vinavyoweza kufanya hivi. Habari mbaya ni kwamba Page Builder Sandwich inatumia nyingi ya sifa na vitendakazi hivi, ambavyo vyote husababisha reflow:

  • elem.getBoundingClientRect()
  • window.getComputedStyle()
  • window.scrollY
  • na mengine mengi…

Suluhisho #1: Kuhifadhi Akiba ya Michakato ya Reflow Inayogharimu Sana

Suluhisho lililo wazi zaidi ni KUTOTUMIA sifa na vitendakazi hivyo. Hata hivyo, PBS inavitegemea sana na hatuwezi kufanya kazi bila hivyo.

Suluhisho tulilobaki nalo ni kupunguza kadiri iwezekanavyo miito kwa vitendakazi hivyo. Sehemu ngumu hapa ilikuwa kwamba tulitumia sifa na vitendakazi hivyo mara nyingi katika sehemu tofauti za PBS, na mara nyingi, tulivitumia kwenye kipengele kile kile cha DOM mara nyingi. Ili kurekebisha hili, tulitengeneza utaratibu wetu wenyewe wa kuweka akiba kwa kila sifa/kitendakazi chenye matatizo.

Kwa mfano, kitendakazi cha getBoundingClientRect  kinatupatia vipimo vya sasa vya pikseli vya juu, kushoto, upana, urefu, kulia, na chini vya kipengele cha DOM. Tunatumia kitendakazi hiki kila wakati kukokotoa mahali pa kuchora mistari ya nje ya vipengele katika PBS. Hapa kuna kitendakazi cha kuweka akiba tulichounda kwa ajili ya hili:

// Akiba: Client rect zetu huwekwa hapa, tunaweza kutumia hii kuzifuta baadaye.
var elemsWithBoundingRects = [];

window.pbsGetBoundingClientRect = function( element ) {

	// Angalia ikiwa tayari tulipata client rect hapo awali.
	if ( ! element._boundingClientRect ) {

		// Ikiwa sivyo, ipate kisha uihifadhi kwa matumizi ya baadaye.
		element._boundingClientRect = element.getBoundingClientRect();
		elemsWithBoundingRects.push( element );
	}
	return element._boundingClientRect;
};
​

Badala ya kuita getBoundingClientRect , sasa tulitumia pbsGetBoundingClientRect . Sasa kila wakati client rect inapoulizwa, tunahifadhi thamani hiyo kwa marejeleo ya baadaye, na hivyo kupunguza idadi ya vichochezi vya reflow.

Pia tulihitaji njia ya kufuta akiba wakati client rect zilizohifadhiwa zinapobatilishwa. Thamani za client rect zilizohifadhiwa hubadilika mtumiaji anaposogeza ukurasa au anapoongeza/kubadilisha/kuondoa vipengele kwenye skrini. Kwa hivyo tulitengeneza kitendakazi cha kusafisha akiba ambacho tunaweza kukiita wakati wowote tunapohitaji thamani mpya za client rect:

var clearClientRects = function() {
	var i;
	for ( i = 0; i < elemsWithBoundingRects.length; i++ ) {
		if ( elemsWithBoundingRects[ i ] ) {
			elemsWithBoundingRects[ i ]._boundingClientRect = null;
		}
	}
	elemsWithBoundingRects = [];
};​

Pia tulifanya utaratibu huu huu wa kuweka akiba kwa miito mingine ya vitendakazi inayochukua rasilimali nyingi ambayo kwa kawaida tunaitumia.

Suluhisho #2: Kukusanya Pamoja Usomaji na Uandishi kwa Kutumia FastDom

Kutekeleza suluhisho #1 kuliongeza utendaji wa PBS, lakini haikutosha.

Kutafuta zaidi kwenye Google, tulikutana na makala ya Wilson Page kuhusu Kuzuia ‘layout thrashing’. Wilson anasema:

Layout Thrashing (reflow) hutokea wakati JavaScript inapoandika na kisha kusoma kwa nguvu kutoka kwa DOM mara nyingi, na kusababisha reflows za waraka.

Inaonekana, haitoshi tu kupunguza miito yako kwa sifa na vitendakazi maalum vinavyochochea reflow. Unapofanya “usomaji” na “uandishi” mwingi unaofuatana kwenye DOM, pia huchochea reflow ya kivinjari. Huu hapa ni mfano wa kawaida, moja kwa moja kutoka kwenye tovuti ya Wilson:

// Soma
var h1 = element1.clientHeight;

// Andika (inabatilisha mpangilio)
element1.style.height = (h1 * 2) + 'px';

// Soma (huchochea reflow)
var h2 = element2.clientHeight;

// Andika (inabatilisha mpangilio)
element2.style.height = (h2 * 2) + 'px';

// Soma (huchochea reflow)
var h3 = element3.clientHeight;

// Andika (inabatilisha mpangilio)
element3.style.height = (h3 * 2) + 'px';

// Reflow ya waraka mwishoni mwa fremu​

Mfano hapo juu unachochea reflows 3 kwa sababu vipimo vya ukurasa mzima hubatilishwa baada ya uandishi. Suluhisho lililopendekezwa kwa hili ni kupanga upya msimbo ili kukusanya pamoja usomaji na uandishi wote ili jambo zima lichochee reflow 1 tu ya kivinjari:

// Soma
var h1 = element1.clientHeight;
var h2 = element2.clientHeight;
var h3 = element3.clientHeight;

// Andika (inabatilisha mpangilio)
element1.style.height = (h1 * 2) + 'px';
element2.style.height = (h2 * 2) + 'px';
element3.style.height = (h3 * 2) + 'px';

// Reflow ya waraka mwishoni mwa fremu​

Kijisehemu cha msimbo hapo juu kinafanya utatuzi wa tatizo uonekane rahisi. Lakini kiuhalisia, katika PBS, kusoma na kuandika mambo yanayochochea reflow hutokea katika sehemu nyingi tofauti kwa nyakati nyingi tofauti wakati wa mzunguko wa maisha wa PBS. Kupanga upya maelfu ya mistari ya msimbo wa Javascript haiwezekani.

Kwa bahati nzuri kwetu, Wilson pia alitoa suluhisho katika makala yake. Aliunda hati ndogo ya matumizi kusaidia kukusanya pamoja usomaji na uandishi huo, inayoitwa FastDom.

Hapa kuna baadhi ya msimbo kutoka kwa Page Builder Sandwich unaotumia FastDom na pia unajumuisha Suluhisho letu #1 hapo juu:

// Kusanya pamoja usomaji kutoka kwenye nyuzi nyingine.
fastdom.measure( function() {

	// Tumia client rect yetu iliyohifadhiwa kwenye akiba.
	var rect = window.pbsGetBoundingClientRect( elem );

	// Kusanya pamoja uandishi kutoka kwenye nyuzi nyingine.
	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 ) );​

Kile ambacho FastDom hufanya ni kwamba inakusanya pamoja miito yote ya fastdom.measure  na miito yote ya fastdom.mutate  na kuitekeleza bila ulandanishi, ikikusanya kwa ufanisi usomaji na uandishi wote pamoja ili kupunguza reflows zote kwenye kivinjari.

Suluhisho #3: Kufikia Vipengee vya Mtindo Kunagharimu Sana

Pia tuligundua kwa msaada wa jsPerf kwamba baadhi ya vitendakazi vya kupata mtindo vilikuwa na kasi zaidi kuliko vingine.

Katika PBS, kwa kawaida tunahitaji kupata thamani ya sasa ya mtindo maalum wa kipengele. Kwa mfano, kwa kawaida tunatumia hii kupata pambizo ya juu:

var styles = window.getComputedStyle( elem );
var marginTop = styles.marginTop;​

Lakini, tuligundua kuwa kufanya hivi kuna kasi zaidi:

var marginTop = elem.style.marginTop;​

Hata hivyo, elem.style.marginTop  na getComputedStyle  ni tofauti sana. Ya kwanza inatupa tu mtindo wa ndani ya mstari wa kipengele, na haizingatii lahajaza mtindo zozote; na ya pili inazingatia mitindo ya ndani ya mstari na lahajaza mtindo.

Zaidi ya hayo ni kwamba hata matokeo ya getComputedStyle  yalipowekwa kwenye akiba, bado yalikuwa ya polepole sana. Kama ilivyobainika, kufikia kipengee cha mtindo chenyewe ndio mchakato wa polepole.

Kwa bahati nzuri kwetu, PBS huongeza mitindo ya ndani ya mstari kwenye vipengele, na kwa kuwa mitindo ya ndani ya mstari hupewa kipaumbele (mara nyingi) kuliko lahajaza mtindo, kutakuwa na matukio ambapo kupata thamani ya mtindo wa ndani ya mstari kutatosha. Kwa hivyo tukichanganya mbinu hizi mbili hapo juu, tunaweza kupata msimbo unaoendeshwa kwa kasi zaidi:

var marginTop = elem.style.marginTop;
if ( ! marginTop ) {
	var styles = window.getComputedStyle( elem );
	marginTop = styles.marginTop;
}​

Matokeo ya Maboresho ya Msimbo

Masuluhisho yetu 3 hapo juu yalichukua utafiti mwingi, majaribio na utekelezaji halisi (na kuchelewesha kipengele chetu cha Fonti kutolewa), lakini mwishowe yote yalikuwa na thamani.

Tukirudi kwenye jaribio letu la awali la kusogeza kipanya chako kwenye skrini kwa sekunde 2. Hapa kuna ratiba ya matukio ya zamani iliyokuwa mbaya/yenye kugugumia:

Na hivi ndivyo ratiba yetu mpya ya matukio inavyoonekana baada ya maboresho ya utendaji:

Kama unavyoona, kuna vitu vichache vya zambarau kwenye grafu. Na kuna tofauti inayoonekana kwenye kiasi cha michakato inayotekelezwa na kivinjari. Vitu vya mstatili vilivyo chini ni vyembamba zaidi pia, kumaanisha michakato inaendeshwa kwa kasi zaidi kuliko hapo awali.

Ukilinganisha kiasi cha maeneo marefu/mapana ya zambarau katika grafu za zamani na mpya, tunaona ongezeko kubwa la utendaji la 200%! Pia tunaona ongezeko la utendaji katika maeneo yote. Si vibaya hata kidogo!

Mambo Muhimu & Mafunzo

Kusema ukweli, hatukufikiri kwamba PBS ilikuwa na matatizo ya utendaji kabla ya Ann kulizungumzia. Hasa kwa sababu tulikuwa tukitumia mashine zilizolenga uundaji na vikwazo vya utendaji havikuwa dhahiri kiasi hicho. Tukiangalia nyuma, kuangalia utendaji kulipaswa kuwa moja ya vipaumbele vya juu. Lakini angalau sasa, kuanzia toleo la 4.3 imeshuhulikiwa. ?

Kwa wale wanaotaka kuboresha utendaji wa programu-jalizi zao wenyewe za WordPress, hasa ikiwa unatumia pia Javascript nzito, haya hapa ni mambo niliyojifunza kutokana na uzoefu huu:

  1. Weka kikomo/weka akiba ya miito yako kwa sifa/vitendakazi vinavyochochea reflow. Tumia hii kama mwongozo: Kinacholazimisha layout/reflow. Orodha ya kina.
  2. Kusanya pamoja “usomaji” na “uandishi” kwa mitindo ya DOM. Tumia FastDom kukufanyia hili.
  3. Tumia Chrome Timeline profiler, na uhakikishe una reflows (vitu vya zambarau) chache iwezekanavyo.