गेल्या २ फेब्रुवारी २०१७ रोजी, अॅन टेलर (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” या लेखात समावेश होईल. तथापि, परफॉर्मन्समुळे तसे झाले नाही. 
त्यामुळे आम्ही अॅन यांना याबद्दल विचारले, आणि त्यांनी उत्तर दिले:
…मी विनामूल्य आवृत्ती थोडी वापरून पाहिली. यात खूप वाव दिसतो: अनेक मॉड्यूल्स, अतिशय सहज समजणारा UI, उत्कृष्ट WYSIWYG अनुभव, सर्व काही सहजपणे ड्रॅग करता येते. तथापि, जेव्हा माझ्या पेजवर सुमारे १० मॉड्यूल्स होते, तेव्हा संपादन गती कमी झाल्यामुळे त्यावर काम सुरू ठेवणे कठीण झाले…
त्यामुळे त्यांच्या मते, Page Builder Sandwich मध्ये परफॉर्मन्सच्या समस्या आहेत. आणि आम्ही नेहमीच अभिप्रायाची दखल घेत असल्याने, आम्ही याची तपासणी केली.
परफॉर्मन्सची चाचणी घेणे
आम्हाला PBS च्या परफॉर्मन्सची तपासणी करण्यासाठी एका मार्गाची गरज होती; PBS प्रामुख्याने जावास्क्रिप्टद्वारे ब्राउझरवर चालत असल्याने, या कामासाठी Chrome चे Timeline profiler हे योग्य साधन होते. टाइमलाइन प्रोफाइलर रनटाइमदरम्यान वेबपेजमध्ये कोणत्या प्रक्रिया सुरू आहेत हे ओळखू शकतो आणि मोजू शकतो, जे गतीतील अडथळे शोधण्यासाठी उत्तम आहे.
आम्हाला वाटले की आम्ही प्रथम सर्वात सोपी पायरी तपासावी – आमचा माउस अनेक घटकांवर आणि ओळींवरून फिरवणे. साधे आहे ना? आम्हाला खात्री होती की इतक्या साध्या गोष्टीत आम्हाला परफॉर्मन्सच्या समस्या येणार नाहीत. दुर्दैवाने, आमचा अंदाज चुकला.
आम्ही रेकॉर्ड बटण दाबल्यावर, सुमारे २ सेकंद स्क्रीनवर माउस फिरवला आणि नंतर स्टॉप बटण दाबले. प्रोफाइलरकडून मिळालेली परिणामी टाइमलाइन येथे आहे:
आणि काय आश्चर्य! यामध्ये परफॉर्मन्सचे अनेक अडथळे भरलेले आहेत!
आलेखामध्ये बऱ्याच गोष्टी घडत आहेत, परंतु सर्वात स्पष्ट समस्या म्हणजे त्यात बरेच जांभळे भाग आहेत (जे नसायला हवेत). त्याहूनही महत्त्वाचे म्हणजे, हे जांभळे भाग स्पष्टपणे खूप रुंद आहेत आणि सर्व आलेखाच्या शिखरावर पोहोचताना दिसतात. तुमच्या हे देखील लक्षात येईल की आलेख नेहमी भरलेला असतो आणि हे जांभळे भाग जवळजवळ कधीही शून्यावर येत नाहीत. असे दिसते की ब्राउझर नेहमी काहीतरी करण्यात व्यस्त आहे आणि जवळजवळ कधीही विश्रांती घेत नाही.
पण त्या सर्व जांभळ्या भागांचा नेमका अर्थ काय आहे?
प्रोफाइलरने आम्हाला सांगितले की त्यांना reflows म्हटले जाते. Google Developer साइट:
Reflow हे दस्तऐवजातील घटकांची स्थाने आणि भूमिती पुन्हा मोजण्यासाठी वेब ब्राउझर प्रक्रियेचे नाव आहे.. रीफ्लो ही ब्राउझरमधील युझर-ब्लॉकिंग ऑपरेशन आहे.
याचा अर्थ असा की PBS मध्ये तुमचा माउस फिरवल्याने प्रचंड प्रमाणात रीफ्लो सुरू होतात. सर्वात वाईट गोष्ट म्हणजे प्रत्येक रीफ्लो ब्राउझरला क्षणभर थांबवतो जेणेकरून तो आपली गणना पूर्ण करू शकेल. अधिक रीफ्लो म्हणजे ब्राउझरला अधिक थांबे आणि अनुभव आणखी जास्त janky. होतो. सोप्या भाषेत सांगायचे तर, बरेच जांभळे भाग = वाईट.
म्हणून असे दिसून आले की अॅनचे म्हणणे बरोबर होते: आमच्याकडे परफॉर्मन्सचा एक मोठा अडथळा नक्कीच आहे, त्यामुळे आमच्या टीमने ते लगेच दुरुस्त करण्याचे काम हाती घेतले.
आमची Reflow / Jank समस्या सोडवणे
इतर कशाच्याही आधी, मुळात या रीफ्लोचे कारण काय आहे हे शोधण्यासाठी आम्हाला काही संशोधन करावे लागले. आम्हाला आढळले की उघडपणे, जावास्क्रिप्टमधील अनेक सामान्य गोष्टींमुळे ब्राउझर रीफ्लो सुरू करू शकतो.
DOM घटकाची रुंदी, उंची किंवा स्थान मिळवण्यासाठी तुम्ही वापरू शकता असे जवळजवळ कोणतेही फंक्शन रीफ्लो ट्रिगर करू शकते. पॉल आयरिश यांनी अशा सर्व गुणधर्मांची आणि फंक्शन्सची सविस्तर यादी लिहिली आहे जी हे करू शकतात. वाईट बातमी अशी आहे की Page Builder Sandwich यापैकी बऱ्याच प्रॉपर्टीज आणि फंक्शन्सचा वापर करते, ज्यामुळे रीफ्लो होतो:
- elem.getBoundingClientRect()
- window.getComputedStyle()
- window.scrollY
- आणि बरेच काही…
फिक्स #१: महागड्या रीफ्लो प्रक्रिया कॅश करणे
सर्वात स्पष्ट उपाय म्हणजे त्या प्रॉपर्टीज आणि फंक्शन्सचा वापर न करणे. तथापि, PBS मोठ्या प्रमाणावर त्यांच्यावर अवलंबून आहे आणि त्यांच्याशिवाय आमचे काम होऊ शकत नाही.
आमच्याकडे उरलेला उपाय म्हणजे त्या फंक्शन्सचे कॉल्स शक्य तितके कमी करणे. यातला कठीण भाग असा होता की आम्ही त्या प्रॉपर्टीज आणि फंक्शन्सचा PBS च्या वेगवेगळ्या भागांमध्ये बऱ्याच वेळा वापर केला होता आणि बहुतांश वेळा आम्ही एकाच DOM घटकावर अनेक वेळा त्यांचा वापर केला होता. हे दुरुस्त करण्यासाठी, आम्ही प्रत्येक समस्याप्रधान प्रॉपर्टी/फंक्शनसाठी आमची स्वतःची कॅशिंग यंत्रणा तयार केली.
उदाहरणार्थ, getBoundingClientRect फंक्शन आपल्याला DOM घटकाचे सध्याचे top, left, width, height, right आणि bottom पिक्सेल मोजमाप देते. 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 चा वापर केला. आता प्रत्येक वेळी क्लायंट रेक्ट विचारले जाते तेव्हा आम्ही ते मूल्य भविष्यातील संदर्भासाठी साठवून ठेवतो, ज्यामुळे रीफ्लो ट्रिगर्सची संख्या मर्यादित होते.
जेव्हा साठवलेले क्लायंट रेक्ट्स अवैध ठरतात तेव्हा कॅशे क्लिअर करण्याचा मार्गही आम्हाला हवा होता. जेव्हा वापरकर्ता पृष्ठ स्क्रोल करतो किंवा स्क्रीनमधील घटक जोडतो/बदलतो/काढून टाकतो तेव्हा साठवलेल्या क्लायंट रेक्टची व्हॅल्यूज बदलतात. म्हणून आम्ही एक कॅशे क्लिअरिंग फंक्शन तयार केले जे आम्ही ताजे क्लायंट रेक्ट व्हॅल्यूज आवश्यक असताना कॉल करू शकतो:
var clearClientRects = function() {
var i;
for ( i = 0; i < elemsWithBoundingRects.length; i++ ) {
if ( elemsWithBoundingRects[ i ] ) {
elemsWithBoundingRects[ i ]._boundingClientRect = null;
}
}
elemsWithBoundingRects = [];
};
आम्ही सहसा वापरत असलेल्या इतर महागड्या फंक्शन कॉल्ससाठीही आम्ही अशीच कॅशिंग यंत्रणा वापरली.
फिक्स #२: FastDom वापरून Reads आणि Writes एकत्र गटबद्ध करणे
फिक्स #१ लागू केल्याने PBS चा परफॉर्मन्स वाढला, पण तो पुरेसा नव्हता.
आणखी थोडे गुगल केल्यावर, आम्हाला विल्सन पेज यांचा ‘layout thrashing’ रोखण्याबाबतचा लेख सापडला. विल्सन म्हणतात:
जेव्हा JavaScript आक्रमकपणे DOM वर वारंवार लिहिते, आणि नंतर वाचते, ज्यामुळे डॉक्युमेंट रीफ्लो होतात, तेव्हा Layout Thrashing (reflow) होते.
वरवर पाहता, विशिष्ट रीफ्लो-ट्रिगर करणाऱ्या प्रॉपर्टीज आणि फंक्शन्सवरील तुमचे कॉल्स मर्यादित करणे पुरेसे नाही. जेव्हा तुम्ही DOM वर एकापाठोपाठ एक अनेक “reads” आणि “writes” करता, तेव्हा ते ब्राउझर रीफ्लो देखील ट्रिगर करते. विल्सन यांच्या साइटवरील ही एक ठराविक परिस्थिती आहे:
// 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
वरील उदाहरण ३ रीफ्लो ट्रिगर करते कारण एका write नंतर संपूर्ण पृष्ठाचे परिमाण अवैध ठरतात. यासाठी सुचवलेला उपाय म्हणजे कोडचा क्रम बदलून सर्व 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 मध्ये, रीफ्लो-ट्रिगर करणाऱ्या गोष्टींचे वाचन आणि लेखन हे PBS च्या लाइफ-सायकल दरम्यान अनेक वेगवेगळ्या वेळी आणि अनेक वेगवेगळ्या ठिकाणी घडते. हजारो ओळींच्या जावास्क्रिप्ट कोडची पुनर्रचना करणे शक्य नव्हते.
आमच्या सुदैवाने, विल्सन यांनी त्यांच्या लेखात एक उपाय देखील दिला होता. त्यांनी ते reads आणि writes एकत्र आणण्यात मदत करण्यासाठी FastDom नावाची एक लहान युटिलिटी स्क्रिप्ट तयार केली.
Page Builder Sandwich मधील काही कोड येथे दिला आहे जो FastDom चा वापर करतो आणि त्यात आमचा वरील फिक्स #१ देखील समाविष्ट आहे:
// 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 कॉल्स एकत्र गटबद्ध करतो आणि ते असिंक्रोनस पद्धतीने चालवतो, ज्यामुळे ब्राउझरमधील सर्व रीफ्लो कमी करण्यासाठी सर्व reads आणि writes प्रभावीपणे एकत्र गटबद्ध होतात.
फिक्स #३: स्टाइल ऑब्जेक्ट्स ॲक्सेस करणे खर्चिक आहे
jsPerf च्या मदतीने आम्हाला हे देखील समजले की काही स्टाइल मिळवणारी फंक्शन्स इतरांपेक्षा वेगवान होती.
PBS मध्ये, आम्हाला सहसा घटकाच्या विशिष्ट स्टाइलचे सध्याचे व्हॅल्यू मिळवण्याची आवश्यकता असते. उदाहरणार्थ, आम्ही सहसा टॉप मार्जिन मिळवण्यासाठी हे वापरतो:
var styles = window.getComputedStyle( elem );
var marginTop = styles.marginTop;
परंतु, आम्हाला आढळले की हे करणे खूप जलद आहे:
var marginTop = elem.style.marginTop;
तथापि, elem.style.marginTop आणि getComputedStyle यात खूप फरक आहे. पहिला पर्याय आपल्याला घटकाचे केवळ इनलाइन स्टाइलिंग देतो आणि कोणत्याही स्टाइलशीटचा विचार करत नाही; आणि दुसरा पर्याय इनलाइन स्टाईल आणि स्टाइलशीट दोन्ही विचारात घेतो.
अधिक म्हणजे, getComputedStyle चा निकाल कॅश केला असला तरीही तो खरोखर संथ होता. दिसून आल्याप्रमाणे, स्टाइल ऑब्जेक्ट स्वतः ॲक्सेस करणे ही संथ प्रक्रिया आहे.
आमच्या सुदैवाने, PBS घटकांना इनलाइन स्टाईल जोडते, आणि इनलाइन स्टाईल स्टाइलशीटपेक्षा (बहुतेक वेळा) प्राधान्य घेत असल्याने, अशा केसेस असतील जिथे इनलाइन स्टाइल व्हॅल्यू मिळवणे पुरेसे असेल. म्हणून जर आपण वरील दोन पद्धती एकत्र केल्या तर आपण अधिक वेगाने चालणारा कोड तयार करू शकतो:
var marginTop = elem.style.marginTop;
if ( ! marginTop ) {
var styles = window.getComputedStyle( elem );
marginTop = styles.marginTop;
}
कोड सुधारणांचे परिणाम
आमच्या वरील ३ उपायांसाठी खूप संशोधन, चाचणी आणि प्रत्यक्ष अंमलबजावणी लागली (आणि यामुळे आमच्या फॉन्ट वैशिष्ट्याचे प्रकाशन लांबणीवर पडले), परंतु शेवटी हे सर्व फायद्याचे ठरले.
स्क्रीनवर २ सेकंद माउस फिरवण्याच्या आमच्या सुरुवातीच्या चाचणीकडे परत वळूया. ही जुनी कुरूप/अडखळणारी टाइमलाइन आहे:
आणि परफॉर्मन्स सुधारणांनंतर आमची नवीन टाइमलाइन कशी दिसते ते येथे आहे:
जसे आपण पाहू शकता, आलेखात जांभळे भाग कमी आहेत. आणि ब्राउझरद्वारे केल्या जाणाऱ्या प्रक्रियांच्या संख्येत लक्षणीय फरक आहे. तळाशी असलेल्या आयताकृती गोष्टी देखील पातळ आहेत, ज्याचा अर्थ प्रक्रिया पूर्वीपेक्षा वेगाने चालवल्या जात आहेत.
जर तुम्ही जुन्या आणि नवीन आलेखांमधील उंच/रुंद जांभळ्या क्षेत्रांच्या प्रमाणाची तुलना केली, तर आपल्याला तब्बल २००% परफॉर्मन्स वाढ पाहायला मिळते! आम्ही सर्वत्र कामगिरीत सुधारणा पाहत आहोत. अजिबात वाईट नाही!
महत्त्वाचे निष्कर्ष आणि शिकण्यासारख्या गोष्टी
प्रामाणिकपणे सांगायचे तर, अॅनने हा मुद्दा उपस्थित करण्यापूर्वी PBS मध्ये परफॉर्मन्सच्या समस्या आहेत असे आम्हाला वाटले नव्हते. मुख्यतः कारण आम्ही विकास-केंद्रित मशिन्स वापरत होतो आणि परफॉर्मन्समधील अडथळे इतके स्पष्ट नव्हते. मागे वळून पाहताना, परफॉर्मन्स तपासणे हे सर्वोच्च प्राधान्यांपैकी एक असायला हवे होते. पण किमान आता, आवृत्ती ४.३ नुसार त्याची काळजी घेण्यात आली आहे. 
ज्यांना त्यांच्या स्वतःच्या वर्डप्रेस प्लगइनचा परफॉर्मन्स सुधारायचा आहे, विशेषत: जर तुम्ही देखील मोठ्या प्रमाणावर जावास्क्रिप्ट वापरत असाल, तर या अनुभवातून मला मिळालेले काही महत्त्वाचे मुद्दे येथे आहेत:
- रीफ्लो ट्रिगर करणाऱ्या प्रॉपर्टीज/फंक्शन्सचे कॉल्स मर्यादित/कॅश करा. मार्गदर्शक म्हणून हे वापरा: What forces layout/reflow. The comprehensive list.
- DOM स्टाईल्सचे “reads” आणि “writes” एकत्र गटबद्ध करा. तुमच्यासाठी हे करण्यासाठी FastDom वापरा.
- Chrome चे Timeline profiler वापरा, आणि तुमच्याकडे शक्य तितके कमी रीफ्लो (जांभळ्या गोष्टी) असल्याची खात्री करा.