HTML5 कैनवस की परफ़ॉर्मेंस को बेहतर बनाना

बोरिस स्मस
बोरिस स्मस

शुरुआती जानकारी

Apple के एक प्रयोग के रूप में शुरू की गई HTML5 कैनवस, वेब पर 2D तुरंत मोड वाले ग्राफ़िक के लिए सबसे ज़्यादा इस्तेमाल किया जाने वाला मानक है. अब कई डेवलपर कई तरह के मल्टीमीडिया प्रोजेक्ट, विज़ुअलाइज़ेशन, और गेम के लिए इस पर भरोसा करते हैं. हालांकि, जैसे-जैसे हम ऐप्लिकेशन की जटिलता बढ़ते जाते हैं, वैसे-वैसे डेवलपर अनजाने में परफ़ॉर्मेंस वॉल को नुकसान पहुंचा देते हैं. कैनवस की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के बारे में, कई ऐसी चीज़ों के बारे में समझौता नहीं है जो अलग-अलग हो सकती हैं. इस लेख का मकसद, इस लेख के कुछ हिस्सों को ऐसे संसाधन में इकट्ठा करना है जिसे डेवलपर आसानी से समझ पाएं. इस लेख में बुनियादी ऑप्टिमाइज़ेशन के बारे में बताया गया है, जो सभी कंप्यूटर ग्राफ़िक एनवायरमेंट के साथ-साथ कैनवस की खास तकनीकों पर लागू होते हैं. कैनवस लागू करने के तरीकों में सुधार होने पर, इन तकनीकों में बदलाव हो सकता है. खास तौर पर, जब ब्राउज़र वेंडर कैनवस जीपीयू ऐक्सेलरेशन को लागू करते हैं, तो यहां बताई गई परफ़ॉर्मेंस से जुड़ी कुछ तकनीकों के बारे में बताया गया है, जो शायद कम असरदार हों. जहां ज़रूरी होगा वहां इसे नोट किया जाएगा. ध्यान दें कि इस लेख में HTML5 कैनवस का इस्तेमाल नहीं किया गया है. इसके लिए, HTML5Rocks पर कैनवस से जुड़े लेख, HTML5 साइट में डाइव करने के बारे में चैप्टर या MDN कैनवस पर मौजूद यह चैप्टर देखें.

परफ़ॉर्मेंस टेस्टिंग

HTML5 कैनवस में तेज़ी से बदलने वाले बदलाव के लिए, JSPerf (jsperf.com) के टेस्ट इस बात की पुष्टि करते हैं कि सुझाया गया हर ऑप्टिमाइज़ेशन अब भी काम कर रहा है. jserf एक वेब ऐप्लिकेशन है. इससे डेवलपर JavaScript की परफ़ॉर्मेंस की जांच कर सकते हैं. हर टेस्ट उस नतीजे पर फ़ोकस करता है जिसे हासिल करने की कोशिश की जा रही है (उदाहरण के लिए, कैनवस को मिटाना). इसमें ऐसे कई तरीके शामिल हैं जो एक ही नतीजा हासिल करते हैं. जेएसपी फ़ंक्शन कम समयावधि में, हर तरीके को ज़्यादा से ज़्यादा बार चलाता है और यह हर सेकंड में आंकड़ों के हिसाब से इतनी बार दोहराता है. ज़्यादा स्कोर हमेशा बेहतर होते हैं! JDBC परफ़ॉर्मेंस की जांच वाले पेज पर आने वाले लोग, अपने ब्राउज़र पर टेस्ट चला सकते हैं. साथ ही, GCPerf को Browserscope (browserscope.org) पर सामान्य जांच के नतीजे स्टोर करने की अनुमति दे सकते हैं. इस लेख में दी गई ऑप्टिमाइज़ेशन की तकनीकों का बैक अप, JSONerf के नतीजे से लिया गया है. इसलिए, आपके पास वापस जाकर अप-टू-डेट जानकारी देखने का विकल्प है कि तकनीक अब भी लागू होती है या नहीं. हमने एक छोटा हेल्पर ऐप्लिकेशन लिखा है, जो इन नतीजों को पूरे लेख में एम्बेड किए गए ग्राफ़ के रूप में रेंडर करता है.

इस लेख में दिए गए सभी परफ़ॉर्मेंस नतीजे, ब्राउज़र वर्शन पर आधारित होते हैं. ऐसा इसलिए होता है, क्योंकि हम नहीं जानते कि ब्राउज़र किस ओएस पर चल रहा था या इससे भी ज़्यादा ज़रूरी बात यह है कि परफ़ॉर्मेंस टेस्ट करने के दौरान HTML5 कैनवस को हार्डवेयर से एक्सेलरेटेड किया गया था या नहीं. पता बार में about:gpu पर जाकर, यह पता लगाया जा सकता है कि Chrome के HTML5 कैनवस पर हार्डवेयर की मदद से तेज़ी लाई गई है या नहीं.

पहले से रेंडर करके, ऑफ़-स्क्रीन कैनवस पर जाएं

अगर आप एक से ज़्यादा फ़्रेम पर स्क्रीन पर मिलते-जुलते प्रिमिटिव फिर से ड्रॉ कर रहे हैं, जैसा कि अक्सर गेम लिखते समय होता है, तो सीन के बड़े हिस्सों को पहले से रेंडर करके ज़्यादा परफ़ॉर्मेंस हासिल की जा सकती है. प्री-रेंडरिंग का मतलब है, अलग से ऑफ़-स्क्रीन कैनवस (या कैनवस) का इस्तेमाल करना, जिस पर कुछ समय के लिए रहने वाली इमेज रेंडर करनी हैं. इसके बाद, ऑफ़-स्क्रीन कैनवस को वापस दिखने वाली कैनवस पर रेंडर करना होता है. उदाहरण के लिए, मान लें कि आप एक सेकंड में 60 फ़्रेम की रफ़्तार से मारियो को फिर से ड्रॉ कर रहे हैं. आप या तो हर एक फ़्रेम में उसकी टोपी, मूंछें, और “M” तैयार कर सकते हैं या ऐनिमेशन चलाने से पहले मारियो को प्री-रेंडर कर सकते हैं. पहले से रेंडर नहीं किया गया है:

// canvas, context are defined
function render() {
  drawMario(context);
  requestAnimationFrame(render);
}

प्री-रेंडरिंग:

var m_canvas = document.createElement('canvas');
m_canvas.width = 64;
m_canvas.height = 64;
var m_context = m_canvas.getContext('2d');
drawMario(m_context);

function render() {
  context.drawImage(m_canvas, 0, 0);
  requestAnimationFrame(render);
}

requestAnimationFrame के इस्तेमाल पर ध्यान दें, जिसके बारे में बाद के सेक्शन में ज़्यादा जानकारी दी गई है.

यह तकनीक खास तौर पर तब असरदार होती है, जब रेंडरिंग की कार्रवाई (ऊपर दिए गए उदाहरण में drawMario) महंगी है. इसका एक अच्छा उदाहरण टेक्स्ट रेंडरिंग है, जो एक बहुत महंगा काम है.

हालांकि, “पहले से रेंडर किया गया ढीला” टेस्ट केस की परफ़ॉर्मेंस खराब है. प्री-रेंडरिंग करते समय, यह पक्का करना ज़रूरी है कि आपका अस्थायी कैनवस, ड्रॉइंग की जा रही इमेज के आस-पास अच्छे से फ़िट हो जाए. अगर ऐसा नहीं है, तो ऑफ़-स्क्रीन रेंडरिंग की परफ़ॉर्मेंस में होने वाला फ़ायदा, एक बड़े कैनवस को दूसरे पर कॉपी करने से परफ़ॉर्मेंस में हुए नुकसान के हिसाब से तय होता है. हालांकि, यह सोर्स टारगेट साइज़ के फ़ंक्शन के हिसाब से अलग-अलग होता है. ऊपर दिए गए टेस्ट में, कैनवस का छोटा हिस्सा दिखाया गया है:

can2.width = 100;
can2.height = 40;

नीचे दिए गए फ़ंक्शन की तुलना में, कम परफ़ॉर्मेंस देने वाले प्लान की तुलना में परफ़ॉर्मेंस खराब होती है:

can3.width = 300;
can3.height = 100;

एक साथ कैनवस कॉल करें

ड्रॉइंग एक महंगा काम है, इसलिए ड्रॉइंग स्टेट मशीन को निर्देशों के एक लंबे सेट के साथ लोड करना बेहतर होता है. इसके बाद, इन सभी को वीडियो बफ़र पर डाल दिया जाता है.

उदाहरण के लिए, कई लाइन बनाते समय, सभी लाइनों वाला एक ही पाथ बनाना और एक ही ड्रॉ कॉल से उसे ड्रॉ करना बेहतर होता है. दूसरे शब्दों में, अलग-अलग लाइन बनाने के बजाय:

for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.beginPath();
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
  context.stroke();
}

एक पॉलीलाइन बनाने से हमें बेहतर परफ़ॉर्मेंस मिलती है:

context.beginPath();
for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
}
context.stroke();

यह बात HTML5 कैनवस की दुनिया पर भी लागू होती है. उदाहरण के लिए, कोई मुश्किल पाथ बनाते समय, सेगमेंट को अलग-अलग रेंडर करने के बजाय, सभी पॉइंट को पाथ में रखना बेहतर होता है (jsperf).

हालांकि, ध्यान दें कि कैनवस में इस नियम का एक अहम अपवाद है: अगर मनचाहे ऑब्जेक्ट को बनाने में शामिल प्रिमिटिव में छोटे बाउंडिंग बॉक्स (उदाहरण के लिए, हॉरिज़ॉन्टल और वर्टिकल लाइनें) हैं, तो उन्हें अलग-अलग रेंडर करना बेहतर हो सकता है (jsperf).

कैनवस की स्थिति में बेवजह बदलाव न करें

HTML5 कैनवस एलिमेंट को स्टेट मशीन के ऊपर लागू किया जाता है, जो फ़िल और स्ट्रोक स्टाइल जैसी चीज़ों को ट्रैक करता है. साथ ही, मौजूदा पाथ बनाने वाले पिछले पॉइंट भी ट्रैक करता है. ग्राफ़िक्स की परफ़ॉर्मेंस को ऑप्टिमाइज़ करते समय, सिर्फ़ ग्राफ़िक रेंडरिंग पर फ़ोकस करना बेहतर होता है. हालांकि, स्टेट मशीन में हेर-फेर करने से परफ़ॉर्मेंस ओवरहेड भी लागू हो सकता है. उदाहरण के लिए, अगर किसी सीन को रेंडर करने के लिए एक से ज़्यादा फ़िल कलर का इस्तेमाल किया जाता है, तो कैनवस पर प्लेसमेंट के बजाय, रंग के हिसाब से रेंडर करना सस्ता होता है. पिनस्ट्रिप पैटर्न को रेंडर करने के लिए, आपके पास धारीदार बनाने, रंग बदलने, अगली धारी को रेंडर करने जैसे काम करने का विकल्प है:

for (var i = 0; i < STRIPES; i++) {
  context.fillStyle = (i % 2 ? COLOR1 : COLOR2);
  context.fillRect(i * GAP, 0, GAP, 480);
}

या फिर सभी विषम धारियों और फिर सभी सम धारियों को रेंडर करें:

context.fillStyle = COLOR1;
for (var i = 0; i < STRIPES/2; i++) {
  context.fillRect((i*2) * GAP, 0, GAP, 480);
}
context.fillStyle = COLOR2;
for (var i = 0; i < STRIPES/2; i++) {
  context.fillRect((i*2+1) * GAP, 0, GAP, 480);
}

उम्मीद के मुताबिक, इंटरलेस वाला तरीका धीमा है, क्योंकि स्टेट मशीन को बदलना महंगा होता है.

सिर्फ़ स्क्रीन के अंतर को रेंडर करें, पूरी नई स्थिति के हिसाब से नहीं

आम तौर पर, स्क्रीन पर ज़्यादा रेंडर करने के मुकाबले, स्क्रीन पर कम इमेज रेंडर करना सस्ता होता है. अगर रीड्रॉ की संख्या में सिर्फ़ अंतर है, तो दोनों को एक साथ करके बेहतर परफ़ॉर्मेंस में बढ़ोतरी की जा सकती है. दूसरे शब्दों में, ड्रॉइंग करने से पहले पूरी स्क्रीन मिटाने के बजाय:

context.fillRect(0, 0, canvas.width, canvas.height);

ड्रॉ किए गए बाउंडिंग बॉक्स को ट्रैक करें और सिर्फ़ उसे मिटाएं.

context.fillRect(last.x, last.y, last.width, last.height);

अगर आपको कंप्यूटर ग्राफ़िक की जानकारी है, तो इस तकनीक को “रीड्रॉ क्षेत्र” के तौर पर भी जाना जा सकता है. इसमें पहले रेंडर किया गया बाउंडिंग बॉक्स सेव किया जाता है और उसे हर रेंडरिंग के बाद मिटा दिया जाता है. यह तकनीक पिक्सल-आधारित रेंडरिंग कॉन्टेक्स्ट पर भी लागू होती है, जैसा कि इस JavaScript Nintendo एम्युलेटर टॉक से दिखाया गया है.

मुश्किल सीन के लिए कई लेयर वाले कैनवस का इस्तेमाल करें

जैसा कि पहले बताया गया है, बड़ी इमेज बनाना महंगा होता है और अगर हो सके, तो इससे बचना चाहिए. ऑफ़ स्क्रीन रेंडर करने के लिए, किसी दूसरे कैनवस का इस्तेमाल करने के अलावा, जैसा कि प्री-रेंडरिंग सेक्शन में दिखाया गया है, हम एक-दूसरे के ऊपर लेयर वाली कैनवस का भी इस्तेमाल कर सकते हैं. फ़ोरग्राउंड कैनवस में पारदर्शिता का इस्तेमाल करके, हम रेंडर होने के समय ऐल्फ़ा को एक साथ कंपोज़ करने के लिए जीपीयू पर भरोसा कर सकते हैं. इसे इस तरह से सेट किया जा सकता है, जिसमें दो कैनवस को बिलकुल सही जगह पर एक के ऊपर रखा गया हो.

<canvas id="bg" width="640" height="480" style="position: absolute; z-index: 0">
</canvas>
<canvas id="fg" width="640" height="480" style="position: absolute; z-index: 1">
</canvas>

यहां सिर्फ़ एक कैनवस होने का फ़ायदा यह है कि जब हम फ़ोरग्राउंड कैनवस को बनाते या हटाते हैं, तो हम बैकग्राउंड में कभी कोई बदलाव नहीं करते. अगर आपके गेम या मल्टीमीडिया ऐप्लिकेशन को फ़ोरग्राउंड और बैकग्राउंड में बांटा जा सकता है, तो इनकी परफ़ॉर्मेंस को बेहतर बनाने के लिए इन्हें अलग-अलग कैनवस पर अपलोड करें.

अक्सर लोगों की आम सोच का फ़ायदा लिया जा सकता है और फ़ोरग्राउंड के मुकाबले बैकग्राउंड को एक बार या धीमी रफ़्तार में रेंडर किया जा सकता है (यह आपके उपयोगकर्ताओं का ध्यान खींच सकता है). उदाहरण के लिए, हर बार रेंडर करने पर फ़ोरग्राउंड को रेंडर किया जा सकता है, लेकिन बैकग्राउंड को सिर्फ़ हर Nवें फ़्रेम को रेंडर किया जा सकता है. इस बात का भी ध्यान रखें कि अगर आपका ऐप्लिकेशन इस तरह की बनावट के साथ बेहतर काम करता है, तो यह तरीका कितनी भी संख्या में कंपोज़िट कैनवस के लिए सबसे सही है.

शैडोब्लर से बचें

कई दूसरे ग्राफ़िक एनवायरमेंट की तरह, HTML5 कैनवस, डेवलपर को प्रिमिटिव को धुंधला करने की सुविधा देता है. हालांकि, यह कार्रवाई बहुत महंगी हो सकती है:

context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = 'rgba(255, 0, 0, 0.5)';
context.fillRect(20, 20, 150, 100);

कैनवस को साफ़ करने के अलग-अलग तरीके जानें

HTML5 कैनवस, ड्रॉइंग का एक तुरंत मोड का उदाहरण है. इसलिए, हर फ़्रेम पर सीन को साफ़ तौर पर फिर से बनाया जाना चाहिए. इसी वजह से, HTML5 कैनवस ऐप्लिकेशन और गेम के लिए, कैनवस को साफ़ करना बुनियादी तौर पर एक ज़रूरी कार्रवाई है. जैसा कि कैनवस की स्थिति में बदलाव करने से बचें सेक्शन में बताया गया है, आम तौर पर पूरे कैनवस को साफ़ करना अच्छा नहीं होता, लेकिन अगर आपको ऐसा करना ज़रूरी है, तो दो विकल्प हैं: context.clearRect(0, 0, width, height) को कॉल करना या ऐसा करने के लिए कैनवस के खास हैक का इस्तेमाल करना: canvas.width = canvas.width;.लिखते समय, clearRect आम तौर पर चौड़ाई को रीसेट करने से बेहतर होता है, लेकिन कुछ मामलों में canvas.width रीसेट करने के हैक का इस्तेमाल Chrome 14 में काफ़ी तेज़ी से किया जा सकता है

इस सलाह से सावधान रहें, क्योंकि यह काफ़ी हद तक कैनवस लागू करने के तरीके पर निर्भर करता है और इसमें बहुत ज़्यादा बदलाव हो सकते हैं. ज़्यादा जानकारी के लिए, कैनवस को मिटाने के बारे में सिमन सेरिस का लेख पढ़ें.

फ़्लोटिंग पॉइंट निर्देशांक से बचें

HTML5 कैनवस में सब-पिक्सल रेंडरिंग की सुविधा काम करती है. इसे बंद करने का कोई तरीका नहीं है. अगर ऐसे निर्देशांक इस्तेमाल किए जाते हैं जो पूर्णांक नहीं हैं, तो लाइनों को बराबर करने के लिए, यह अपने-आप एंटी-एलियासिंग का इस्तेमाल करता है. यहां विज़ुअल इफ़ेक्ट दिया गया है, जिसे सेब ली-डेलिसल के इस सब-पिक्सल कैनवस परफ़ॉर्मेंस लेख से लिया गया है:

सब-पिक्सल

अगर स्मूद स्प्राइट से आपको मनचाहा इफ़ेक्ट नहीं मिलता, तो Math.floor या Math.round (jsperf) का इस्तेमाल करके, अपने निर्देशांकों को पूर्णांक में बदलना ज़्यादा तेज़ हो सकता है:

अपने फ़्लोटिंग पॉइंट निर्देशांक को पूर्णांक में बदलने के लिए, कई समझदारी भरी तकनीकों का इस्तेमाल किया जा सकता है. इनमें से सबसे ज़्यादा काम करने वाली तकनीकों में, टारगेट की गई संख्या में आधे को जोड़ना और फिर फ़्रैक्शनल वाले हिस्से को हटाने के लिए, नतीजे पर बिट के हिसाब से कार्रवाइयां करना शामिल है.

// With a bitwise or.
rounded = (0.5 + somenum) | 0;
// A double bitwise not.
rounded = ~~ (0.5 + somenum);
// Finally, a left bitwise shift.
rounded = (0.5 + somenum) << 0;

परफ़ॉर्मेंस का पूरा ब्रेकडाउन यहां दिया गया है (jsperf).

ध्यान दें कि कैनवस लागू करने के बाद, इस तरह के ऑप्टिमाइज़ेशन का कोई असर नहीं पड़ता क्योंकि यह एक बार लागू हो जाने के बाद जीपीयू पर लागू होता है. इसकी मदद से, बिना पूर्णांक वाले निर्देशांक तुरंत रेंडर किए जा सकते हैं.

requestAnimationFrame की मदद से अपने ऐनिमेशन ऑप्टिमाइज़ करें

ब्राउज़र में इंटरैक्टिव ऐप्लिकेशन लागू करने के लिए, नया requestAnimationFrame एपीआई इस्तेमाल करने का सुझाव दिया जाता है. ब्राउज़र को किसी तय टिक रेट पर रेंडर करने का निर्देश देने के बजाय, ब्राउज़र को अपने रेंडरिंग रूटीन को कॉल करने के लिए कहें. इसके बजाय, ब्राउज़र उपलब्ध होने पर उसे कॉल करें. इसका अच्छी बात यह है कि अगर पेज फ़ोरग्राउंड में नहीं है, तो ब्राउज़र इतनी समझदार है कि उसे रेंडर नहीं कर पाएगा. requestAnimationFrame कॉलबैक का लक्ष्य 60 FPS (फ़्रेम प्रति सेकंड) कॉलबैक रेट है, लेकिन यह इसकी गारंटी नहीं देता. इसलिए, आपको यह ट्रैक करना होगा कि पिछली इमेज को रेंडर होने के बाद से कितना समय बीता है. यह कुछ ऐसा दिख सकता है:

var x = 100;
var y = 100;
var lastRender = Date.now();
function render() {
  var delta = Date.now() - lastRender;
  x += delta;
  y += delta;
  context.fillRect(x, y, W, H);
  requestAnimationFrame(render);
}
render();

ध्यान दें कि requestAnimationFrame का यह इस्तेमाल, कैनवस के साथ-साथ WebGL जैसी रेंडरिंग की दूसरी टेक्नोलॉजी पर भी लागू होता है. ईमेल लिखते समय, यह एपीआई सिर्फ़ Chrome, Safari, और Firefox में उपलब्ध है. इसलिए, आपको इस शिम का इस्तेमाल करना चाहिए.

ज़्यादातर मोबाइल कैनवस लागू होने में ज़्यादा समय लग रहा है

चलिए, मोबाइल के बारे में बात करते हैं. माफ़ करें, गलती से Safari 5.1 पर चलने वाले iOS 5.0 बीटा वर्शन में ही जीपीयू एक्सेलरेटेड मोबाइल कैनवस लागू करने की सुविधा है. जीपीयू ऐक्सेलरेशन के बिना, मोबाइल ब्राउज़र में कैनवस पर आधारित मॉडर्न ऐप्लिकेशन के लिए आम तौर पर, ज़रूरत के मुताबिक सीपीयू नहीं होते. ऊपर बताए गए कई {9/}erf टेस्ट, डेस्कटॉप की तुलना में मोबाइल पर बहुत ज़्यादा खराब काम करते हैं. इससे क्रॉस-डिवाइस ऐप्लिकेशन के उन टाइप को सीमित कर दिया जाता है जिन्हें अच्छी तरह से चलाया जा सकता है.

नतीजा

रीकैप के लिए, इस लेख में उपयोगी ऑप्टिमाइज़ेशन तकनीकों के एक सेट के बारे में बताया गया है, जिनसे आपको बेहतर परफ़ॉर्मेंस देने वाले HTML5 कैनवस-आधारित प्रोजेक्ट बनाने में मदद मिलेगी. अब जब आपने यहां कुछ नया सीखा है, तो आगे बढ़ें और अपने शानदार क्रिएशन को ऑप्टिमाइज़ करें. अगर आपके पास फ़िलहाल ऑप्टिमाइज़ करने के लिए कोई गेम या ऐप्लिकेशन नहीं है, तो बेहतर आइडिया पाने के लिए Chrome के एक्सपेरिमेंट और क्रिएटिव JS देखें.

References

  • तुरंत मोड बनाम रिटेन किया गया मोड.
  • अन्य HTML5Rocks कैनवस लेख.
  • HTML5 में डाइव का कैनवस सेक्शन.
  • JSPerf की मदद से डेवलपर, JS परफ़ॉर्मेंस की जांच कर सकते हैं.
  • Browserscope की मदद से ब्राउज़र की परफ़ॉर्मेंस का डेटा सेव होता है.
  • JSPerfView, जो JPEGrf टेस्ट को चार्ट के तौर पर रेंडर करता है.
  • साइमन की यह ब्लॉग पोस्ट, कैनवस हटाने के बारे में है. साथ ही, उनकी किताब, HTML5 Unleashed, जिसमें कैनवस की परफ़ॉर्मेंस पर एक चैप्टर भी शामिल है.
  • सब-पिक्सल रेंडरिंग की परफ़ॉर्मेंस के बारे में सेबेस्टियन की ब्लॉग पोस्ट.
  • JS NES एम्युलेटर को ऑप्टिमाइज़ करने के बारे में बेन की बात.
  • Chrome DevTools में नया कैनवस प्रोफ़ाइलर.