අප අපගේ ප්ලගිනයේ කාර්යසාධනය 200%කින් වැඩි කළ ආකාරය

ලියන ලද්දේ

තුළ

,

පසුගිය 2017 පෙබරවාරි 2 වන දින, Ann Taylor විසින් CodeInWP හි 12 Things We Need to See From WordPress Page Builders in 2017 + Who Already Gets It Right යන ලිපිය ලියන ලදී. අපි වසරකට වැඩි කාලයක් තිස්සේ Page Builder Sandwich අඛණ්ඩව වැඩිදියුණු කරමින් සිටිමු: අපි අපගේ පර්යේෂණ සිදු කරමු, අපගේ පාරිභෝගිකයින්ට සවන් දෙමු, එබැවින් Page Builder Sandwich CodeInWP හි “Who Got it Right” ලිපියට ඇතුළත් වනු ඇතැයි අපි සිතුවෙමු. කෙසේ වෙතත්, ක්‍රියාකාරීත්වයේ (performance) ගැටලු හේතුවෙන් අපට ඊට ඇතුළත් වීමට නොහැකි විය. ?

එබැවින් අපි මේ ගැන Ann ගෙන් විමසූ අතර ඇය මෙසේ පිළිතුරු දුන්නාය:

…මම නොමිලේ ලබා දෙන සංස්කරණය (free version) මඳක් අත්හදා බැලුවෙමි. එය විශාල බලාපොරොත්තුවක් පෙන්වයි: මොඩියුල විශාල ප්‍රමාණයක්, ඉතා පහසු UI එකක්, විශිෂ්ට WYSIWYG අත්දැකීමක්, සියල්ල පහසුවෙන්ම ඇදගෙන යා හැක (dragged around). කෙසේ වෙතත්, පිටුවේ මොඩියුල 10ක් පමණ තිබූ විට, අඩු සංස්කරණ වේගය නිසා එය සමඟ දිගටම වැඩ කිරීම අපහසු විය…

එබැවින් ඇයට අනුව, Page Builder Sandwich හි ක්‍රියාකාරීත්ව ගැටලු තිබේ. අපි සැමවිටම ප්‍රතිපෝෂණවලට සවන් දෙන බැවින්, අපි එය පරීක්ෂා කර බැලුවෙමු.

ක්‍රියාකාරීත්වය පරීක්ෂා කිරීම

PBS හි ක්‍රියාකාරීත්වය පරීක්ෂා කිරීමට අපට ක්‍රමයක් අවශ්‍ය විය; PBS ප්‍රධාන වශයෙන් Javascript හරහා බ්‍රව්සරය තුළ ධාවනය වන බැවින්, Chrome හි Timeline profiler ඒ සඳහා වඩාත් සුදුසු මෙවලම විය. Timeline profiler මඟින් ධාවන කාලය තුළ වෙබ් පිටුවක සිදුවන ක්‍රියාවලි හඳුනා ගැනීමට සහ මැනීමට හැකි අතර, එය වේගය අඩාල වන ස්ථාන (bottlenecks) සොයා ගැනීමට පරිපූර්ණ වේ.

අපි මුලින්ම වඩාත් සරල පියවර පරීක්ෂා කළ යුතු යැයි සිතුවෙමු – මූලද්‍රව්‍ය (elements) සහ පේළි (rows) කිහිපයක් හරහා අපගේ මවුසය ගෙන යාම. සරලයි නේද? මෙවැනි සරල දෙයකින් අපට ක්‍රියාකාරීත්ව ගැටලු ඇති නොවන බව අපට විශ්වාස විය. අවාසනාවකට, අප වැරදි විය.

අපි රෙකෝඩ් බොත්තම ක්ලික් කළ පසු, තිරය මත තත්පර 2ක් පමණ මවුසය ගෙන ගොස් නැවතුම් බොත්තම එබුවෙමු. ප්‍රොෆයිලරයෙන් ලැබුණු ප්‍රතිඵල ටයිම්ලයින් එක මෙන්න:

පුදුමයකි! එය සම්පූර්ණයෙන්ම ක්‍රියාකාරීත්ව බාධාවලින් (bottlenecks) පිරී තිබුණි!

ප්‍රස්තාරයේ බොහෝ දේ සිදුවෙමින් පවතින නමුත්, වඩාත්ම පැහැදිලි ගැටලුව වන්නේ එහි දම් පැහැති ප්‍රදේශ විශාල ප්‍රමාණයක් තිබීමයි (එසේ නොවිය යුතුය). ඊට අමතරව, මෙම දම් පැහැති ප්‍රදේශ ඉතා පළල් වන අතර, සියල්ලම ප්‍රස්තාරයේ උපරිමයට ළඟා වන බවක් පෙනේ. ප්‍රස්තාරය සැමවිටම පිරී ඇති බවත්, දම් පැහැති ප්‍රදේශ කිසි විටෙකත් පාහේ බිංදුවට නොවැටෙන බවත් ඔබට පෙනෙනු ඇත. බ්‍රව්සරය සැමවිටම යම් දෙයක් කරමින් කාර්යබහුලව සිටින බවත්, කිසි විටෙකත් විවේක නොගන්නා බවත් පෙනේ.

නමුත් එම දම් පැහැති ප්‍රදේශවලින් සැබවින්ම අදහස් කරන්නේ කුමක්ද?

ඒවා reflows ලෙස හඳුන්වන බව ප්‍රොෆයිලරය අපට කාරුණිකව පෙන්වා දුන්නේය. Google Developer වෙබ් අඩවියෙන්:

ලේඛනයේ ඇති මූලද්‍රව්‍යවල පිහිටීම් සහ ජ්‍යාමිතිය (positions and geometries) නැවත ගණනය කිරීම සඳහා වන වෙබ් බ්‍රව්සර් ක්‍රියාවලියේ නම Reflow වේ.. reflow යනු බ්‍රව්සරයේ පරිශීලකයා අවහිර කරන (user-blocking) ක්‍රියාවලියකි.

එබැවින් මෙයින් අදහස් කරන්නේ PBS තුළ ඔබේ මවුසය එහා මෙහා ගෙන යාමෙන් විශාල reflows ප්‍රමාණයක් ක්‍රියාත්මක වන බවයි. වඩාත් නරක වන්නේ එක් එක් reflow මඟින් එහි ගණනය කිරීම් අවසන් කිරීමට හැකි වන පරිදි මොහොතකට බ්‍රව්සරය නවතා දැමීමයි. වැඩි reflows ප්‍රමාණයක් යනු වැඩි බ්‍රව්සර් නැවතීම් වන අතර, අත්දැකීම තවත් අක්‍රමවත් (janky) වේ. සරලව කිවහොත්, දම් පැහැති ප්‍රදේශ ගොඩක් = නරකයි.

එබැවින් Ann නිවැරදි බව පෙනී ගියේය: අපට විශාල කාර්යසාධන බාධාවක් (bottleneck) තිබූ අතර, අපගේ කණ්ඩායම වහාම එය නිවැරදි කිරීමට කටයුතු කළේය.

අපගේ Reflow / Jank ගැටලුව නිරාකරණය කිරීම

අනෙක් සියල්ලටම පෙර, මෙම reflow එක ඇතිවීමට මූලික හේතුව කුමක්දැයි සොයා බැලීමට අපට යම් පර්යේෂණයක් කිරීමට අවශ්‍ය විය. පෙනෙන විදිහට, Javascript හි ඇති බොහෝ සාමාන්‍ය දේවල් මඟින් බ්‍රව්සරයට reflow එකක් ඇති කිරීමට පෙළඹවිය හැකි බව අපට පෙනී ගියේය.

DOM මූලද්‍රව්‍යයක පළල, උස හෝ පිහිටීම ලබා ගැනීමට ඔබට භාවිතා කළ හැකි ඕනෑම ශ්‍රිතයකට (function) පාහේ reflow එකක් ඇති කළ හැක. Paul Irish විසින් මෙය කළ හැකි Javascript හි සියලුම properties සහ functions පිළිබඳ සවිස්තරාත්මක ලැයිස්තුවක් ලියා ඇත. නරක ආරංචිය නම් Page Builder Sandwich මෙම properties සහ functions විශාල ප්‍රමාණයක් භාවිතා කරන අතර, ඒවා සියල්ලම reflow ඇති කරයි:

  • elem.getBoundingClientRect()
  • window.getComputedStyle()
  • window.scrollY
  • සහ තවත් බොහෝ දේ…

පිළියම #1: වියදම් අධික Reflow ක්‍රියාවලි හැඹිලිගත කිරීම (Caching)

වඩාත්ම පැහැදිලි විසඳුම වන්නේ එම properties සහ functions භාවිතා නොකිරීමයි. කෙසේ වෙතත්, PBS ඒවා මත දැඩි ලෙස රඳා පවතින අතර ඒවා නොමැතිව අපට කළ නොහැක.

අපට ඉතිරිව ඇති විසඳුම වන්නේ එම ශ්‍රිතයන් වෙත කරන ඇමතුම් (calls) හැකිතාක් දුරට අඩු කිරීමයි. මෙහි ඇති දුෂ්කර කොටස වූයේ අපි එම properties සහ functions PBS හි විවිධ කොටස්වල බොහෝ වාරයක් භාවිතා කර තිබීම සහ බොහෝ විට එකම DOM මූලද්‍රව්‍යය මත කිහිප වතාවක් භාවිතා කර තිබීමයි. මෙය නිවැරදි කිරීම සඳහා, අපි එක් එක් ගැටළු සහගත property/function සඳහා අපගේම හැඹිලිගත කිරීමේ ක්‍රමවේදයක් (caching mechanism) නිර්මාණය කළෙමු.

උදාහරණයක් ලෙස, getBoundingClientRect ශ්‍රිතය මඟින් DOM මූලද්‍රව්‍යයක වත්මන් top, left, width, height, right, සහ bottom පික්සෙල් මිනුම් ලබා දෙයි. PBS හි මූලද්‍රව්‍ය දළ සටහන් (outlines) අඳින්නේ කොතැනදැයි ගණනය කිරීමට අපි මෙම ශ්‍රිතය නිතරම භාවිතා කරමු. මේ සඳහා අප නිර්මාණය කළ caching function එක මෙන්න:

// 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 rects අවලංගු වන විට හැඹිලිය (cache) හිස් කිරීමටද අපට ක්‍රමයක් අවශ්‍ය විය. පරිශීලකයා පිටුව අනුචලනය (scroll) කරන විට හෝ තිරයේ මූලද්‍රව්‍ය එක් කරන/වෙනස් කරන/ඉවත් කරන විට ගබඩා කර ඇති client rect අගයන් වෙනස් වේ. එබැවින් අපට නැවුම් client rect අගයන් අවශ්‍ය වන සෑම අවස්ථාවකම ඇමතිය හැකි cache clearing ශ්‍රිතයක් අප විසින් නිර්මාණය කරන ලදී:

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

අප සාමාන්‍යයෙන් භාවිතා කරන අනෙකුත් වියදම් අධික ශ්‍රිත ඇමතුම් සඳහාද අපි මෙම caching ක්‍රමවේදයම ක්‍රියාත්මක කළෙමු.

පිළියම #2: FastDom භාවිතයෙන් Reads සහ Writes එකට කාණ්ඩගත කිරීම

පිළියම #1 ක්‍රියාත්මක කිරීමෙන් PBS හි ක්‍රියාකාරීත්වය වැඩි වූ නමුත් එය ප්‍රමාණවත් නොවීය.

තවදුරටත් ගූගල් කිරීමේදී, Wilson Page විසින් රචිත Preventing ‘layout thrashing’ පිළිබඳ ලිපියක් අපට හමු විය. Wilson මෙසේ පවසයි:

JavaScript විසින් DOM එකෙන් කිහිප වතාවක් එක දිගට ලියන (writes) සහ කියවන (reads) විට Layout Thrashing (reflow) සිදුවන අතර එමඟින් ලේඛන reflows ඇතිවේ.

පෙනෙන විදිහට, reflow ඇති කරන නිශ්චිත properties සහ functions සඳහා වන ඇමතුම් සීමා කිරීම පමණක් ප්‍රමාණවත් නොවේ. ඔබ DOM මත අඛණ්ඩව “reads” සහ “writes” කිහිපයක් සිදු කරන විට, එයද බ්‍රව්සර් reflow එකක් ඇති කරයි. Wilson ගේ වෙබ් අඩවියෙන්ම ලබාගත් සාමාන්‍ය අවස්ථාවක් මෙන්න:

// 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​

ඉහත උදාහරණය මඟින් reflows 3ක් ක්‍රියාත්මක කරන්නේ write කිරීමකින් පසුව සම්පූර්ණ පිටුවේම මානයන් (dimensions) අවලංගු වන බැවිනි. මේ සඳහා යෝජිත විසඳුම වන්නේ මුළු ක්‍රියාවලියෙන්ම බ්‍රව්සර් reflow 1ක් පමණක් ක්‍රියාත්මක වන පරිදි සියලුම reads සහ writes එකට කාණ්ඩගත කිරීම සඳහා කේතය නැවත සකස් කිරීමයි:

// 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 කේත පේළි දහස් ගණනක් නැවත සංවිධානය කිරීම ප්‍රායෝගික නොවේ.

අපගේ වාසනාවකට මෙන්, Wilson ඔහුගේ ලිපියෙහි විසඳුමක් ද ලබා දී තිබුණි. ඔහු එම reads සහ writes එකට කාණ්ඩගත කිරීමට උදවු කිරීම සඳහා FastDom නමින් කුඩා උපයෝගිතා ස්ක්‍රිප්ටයක් (utility script) නිර්මාණය කර තිබුණි.

FastDom භාවිතා කරන සහ ඉහත අපගේ පිළියම #1 ද ඇතුළත් Page Builder Sandwich හි කේත කිහිපයක් මෙන්න:

// 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 ඇමතුම් එකට කාණ්ඩ කර ඒවා අසමමුහුර්තව (asynchronously) ක්‍රියාත්මක කිරීමයි. එමඟින් බ්‍රව්සරයේ සියලුම reflows අඩු කිරීම සඳහා සියලුම reads සහ writes ඵලදායී ලෙස එකට කාණ්ඩගත කරයි.

පිළියම #3: Style Objects වෙත ප්‍රවේශ වීම වියදම් අධිකය

සමහර style ලබා ගන්නා ශ්‍රිත අනෙක් ඒවාට වඩා වේගවත් බව jsPerf ආධාරයෙන් අපි සොයා ගත්තෙමු.

PBS හි, අපට සාමාන්‍යයෙන් මූලද්‍රව්‍යයක නිශ්චිත style එකක වත්මන් අගය ලබා ගැනීමට අවශ්‍ය වේ. උදාහරණයක් ලෙස, ඉහළ මායිම (top margin) ලබා ගැනීමට අපි සාමාන්‍යයෙන් මෙය භාවිතා කරමු:

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

නමුත්, මෙය කිරීම ඊට වඩා බෙහෙවින් වේගවත් බව අපි සොයා ගත්තෙමු:

var marginTop = elem.style.marginTop;​

කෙසේ වෙතත්, elem.style.marginTop සහ getComputedStyle යනු බෙහෙවින් වෙනස් දෙකකි. පළමුවැන්න අපට මූලද්‍රව්‍යයේ inline styling පමණක් ලබා දෙන අතර කිසිදු stylesheet එකක් සැලකිල්ලට නොගනී; දෙවැන්න inline styles සහ stylesheets යන දෙකම සැලකිල්ලට ගනී.

ඊටත් වඩා, getComputedStyle ප්‍රතිඵලය cache කර තිබියදී පවා, එය තවමත් ඉතා මන්දගාමී විය. පෙනී ගිය පරිදි, style object එකට ප්‍රවේශ වීමම මන්දගාමී ක්‍රියාවලියකි.

අපගේ වාසනාවට, PBS මූලද්‍රව්‍ය වෙත inline styles එකතු කරන අතර (බොහෝ විට) stylesheets වලට වඩා inline styles වලට ප්‍රමුඛත්වය ලැබෙන බැවින්, inline style අගය ලබා ගැනීම ප්‍රමාණවත් වන අවස්ථා තිබේ. එබැවින් අපි ඉහත ක්‍රම දෙක ඒකාබද්ධ කළහොත්, අපට වඩා වේගයෙන් ක්‍රියාත්මක වන කේතයක් ලබා ගත හැක:

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

කේත වැඩිදියුණු කිරීම්වල ප්‍රතිඵල

අපගේ ඉහත පිළියම් 3 සඳහා විශාල පර්යේෂණයක්, පරීක්ෂා කිරීමක් සහ සැබෑ ක්‍රියාත්මක කිරීමක් අවශ්‍ය විය (සහ අපගේ Fonts විශේෂාංගය නිකුත් කිරීම ප්‍රමාද විය), නමුත් අවසානයේ ඒ සියල්ල ඉතා වටිනා විය.

තත්පර 2ක් තිරය හරහා මවුසය ගෙන යාමේ අපගේ මූලික පරීක්ෂණය වෙත නැවත යමු. මෙන්න පැරණි කැත/අක්‍රමවත් timeline එක:

ක්‍රියාකාරීත්ව වැඩිදියුණු කිරීම්වලින් පසුව අපගේ නව timeline එක පෙනෙන්නේ මෙසේය:

ඔබට පෙනෙන පරිදි, ප්‍රස්තාරයේ දම් පැහැති කොටස් අඩුය. තවද බ්‍රව්සරය මඟින් සිදු කරන ක්‍රියාවලි ප්‍රමාණයේ සැලකිය යුතු වෙනසක් ඇත. පතුලේ ඇති සෘජුකෝණාස්‍රාකාර කොටස් ද වඩා සිහින් වී ඇති අතර, එයින් අදහස් වන්නේ ක්‍රියාවලි පෙරට වඩා වේගයෙන් ධාවනය වන බවයි.

ඔබ පැරණි සහ නව ප්‍රස්තාරවල උස/පළල් දම් පැහැති ප්‍රදේශ ප්‍රමාණය සංසන්දනය කරන්නේ නම්, අපි විශාල 200% ක ක්‍රියාකාරීත්ව වර්ධනයක් දකිමු! සෑම අතින්ම ක්‍රියාකාරීත්වයේ වැඩිවීමක්ද අපි දකිමු. කිසිසේත්ම නරක නැත!

උගත් පාඩම් සහ මතක තබා ගත යුතු දෑ

අවංකවම කිවහොත්, Ann එය පෙන්වා දීමට පෙර PBS හි ක්‍රියාකාරීත්ව ගැටලු ඇතැයි අපි නොසිතුවෙමු. ප්‍රධාන වශයෙන් අප සංවර්ධනය කේන්ද්‍ර කරගත් උපාංග (development-centric machines) භාවිතා කළ නිසා ක්‍රියාකාරීත්ව බාධාවන් එතරම් පැහැදිලි නොවීය. ආපසු හැරී බලන විට, ක්‍රියාකාරීත්වය පරීක්ෂා කිරීම ප්‍රමුඛතා අතර ඉහළින්ම තිබිය යුතුව තිබුණි. නමුත් අවම වශයෙන් දැන්, 4.3 වන සංස්කරණය අනුව එය නිරාකරණය කර ඇත. ?

තමන්ගේම WordPress ප්ලගිනයේ ක්‍රියාකාරීත්වය වැඩිදියුණු කිරීමට කැමති අයට, විශේෂයෙන් ඔබත් බරපතල ලෙස Javascript භාවිතා කරන්නේ නම්, මෙම අත්දැකීමෙන් මා උගත් දේ මෙන්න:

  1. Reflow ඇති කරන properties/functions වෙත ඔබගේ ඇමතුම් සීමා කරන්න/හැඹිලිගත කරන්න (cache). මෙය මඟ පෙන්වීමක් ලෙස භාවිතා කරන්න: What forces layout/reflow. The comprehensive list.
  2. DOM styles වෙත “reads” සහ “writes” එකට කාණ්ඩගත කරන්න. ඔබ වෙනුවෙන් මෙය සිදු කිරීමට FastDom භාවිතා කරන්න.
  3. Chrome හි Timeline profiler භාවිතා කරන්න, සහ හැකිතාක් අඩුවෙන් reflows (දම් පැහැති කොටස්) ඇති බවට වග බලා ගන්න.