पब्लिश किया गया: 31 मार्च, 2014
रेंडरिंग पाथ की परफ़ॉर्मेंस में आने वाली समस्याओं की पहचान करने और उन्हें ठीक करने के लिए, आम तौर पर होने वाली गड़बड़ियों के बारे में अच्छी जानकारी होना ज़रूरी है. परफ़ॉर्मेंस के सामान्य पैटर्न की पहचान करने के लिए, निर्देशों वाले टूर की मदद से अपने पेजों को ऑप्टिमाइज़ किया जा सकता है.
क्रिटिकल रेंडरिंग पाथ को ऑप्टिमाइज़ करने से, ब्राउज़र पेज को ज़्यादा से ज़्यादा तेज़ी से पेंट कर पाता है: तेज़ी से लोड होने वाले पेजों से दर्शकों की दिलचस्पी बढ़ती है, ज़्यादा पेज देखे जाते हैं, और कन्वर्ज़न में बढ़ोतरी होती है. विज़िटर को खाली स्क्रीन देखने में लगने वाले समय को कम करने के लिए, हमें यह तय करना होगा कि कौनसे रिसॉर्स लोड किए जाएं और किस क्रम में.
इस प्रोसेस को समझाने के लिए, सबसे आसान मामले से शुरू करें. इसके बाद, ज़्यादा संसाधनों, स्टाइल, और ऐप्लिकेशन लॉजिक को शामिल करने के लिए, अपने पेज को धीरे-धीरे बनाएं. इस प्रोसेस में, हम हर मामले को ऑप्टिमाइज़ करेंगे. साथ ही, यह भी देखेंगे कि कहां गड़बड़ी हो सकती है.
अब तक हमने सिर्फ़ इस बात पर फ़ोकस किया है कि रिसॉर्स (सीएसएस, JS या एचटीएमएल फ़ाइल) प्रोसेस होने के बाद, ब्राउज़र में क्या होता है. हमने कैश मेमोरी या नेटवर्क से संसाधन को फ़ेच करने में लगने वाले समय को अनदेखा किया है. हम इन बातों को मानकर चलेंगे:
- सर्वर तक नेटवर्क में दोतरफ़ा यात्रा (प्रोपगेशन लेटेंसी) में 100 मिलीसेकंड लगते हैं.
- एचटीएमएल दस्तावेज़ के लिए, सर्वर से जवाब मिलने में 100 मिलीसेकंड और अन्य सभी फ़ाइलों के लिए 10 मिलीसेकंड लगते हैं.
Hello world का अनुभव
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Critical Path: No Style</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
बुनियादी एचटीएमएल मार्कअप और एक इमेज से शुरू करें. इसमें सीएसएस या JavaScript का इस्तेमाल न करें. इसके बाद, Chrome DevTools में नेटवर्क पैनल खोलें और उससे मिलने वाले रिसॉर्स वॉटरफ़ॉल की जांच करें:
उम्मीद के मुताबिक, एचटीएमएल फ़ाइल को डाउनलोड होने में करीब 200 मिलीसेकंड लगे. ध्यान दें कि नीली लाइन के पारदर्शी हिस्से से पता चलता है कि ब्राउज़र ने नेटवर्क से कोई रिस्पॉन्स बाइट मिलने से पहले कितनी देर इंतज़ार किया. वहीं, सॉलिड हिस्से से पता चलता है कि रिस्पॉन्स बाइट मिलने के बाद, डाउनलोड पूरा होने में कितना समय लगा. एचटीएमएल डाउनलोड बहुत छोटा (<4K) होता है. इसलिए, पूरी फ़ाइल को फ़ेच करने के लिए, हमें सिर्फ़ एक राउंड ट्रिप की ज़रूरत होती है. इस वजह से, HTML दस्तावेज़ को फ़ेच करने में करीब 200 मिलीसेकंड लगते हैं. इसमें से आधा समय नेटवर्क के इंतज़ार में और आधा समय सर्वर के रिस्पॉन्स के इंतज़ार में बीतता है.
जब एचटीएमएल कॉन्टेंट उपलब्ध हो जाता है, तो ब्राउज़र बाइट को पार्स करता है, उन्हें टोकन में बदलता है, और डीओएम ट्री बनाता है. ध्यान दें कि DevTools, DOMContentLoaded इवेंट के लिए नीचे (216 मिलीसेकंड) आसानी से समय की जानकारी देता है. यह समय, नीली वर्टिकल लाइन से भी मेल खाता है. एचटीएमएल डाउनलोड होने के आखिर और नीली वर्टिकल लाइन (DOMContentLoaded) के बीच का अंतर, ब्राउज़र को DOM ट्री बनाने में लगने वाला समय होता है. इस मामले में, यह अंतर सिर्फ़ कुछ मिलीसेकंड का है.
ध्यान दें कि हमारी "शानदार फ़ोटो" ने domContentLoaded
इवेंट को ब्लॉक नहीं किया. हम पेज पर मौजूद हर ऐसेट के लोड होने का इंतज़ार किए बिना, रेंडर ट्री बना सकते हैं और पेज को पेंट भी कर सकते हैं: फ़र्स्ट पेंट को तेज़ी से डिलीवर करने के लिए, सभी रिसॉर्स ज़रूरी नहीं हैं. असल में, जब हम क्रिटिकल रेंडरिंग पाथ के बारे में बात करते हैं, तो आम तौर पर हम एचटीएमएल मार्कअप, सीएसएस, और JavaScript के बारे में बात कर रहे होते हैं. इमेज, पेज के शुरुआती रेंडर को ब्लॉक नहीं करती हैं. हालांकि, हमें इमेज को जल्द से जल्द पेंट करने की कोशिश करनी चाहिए.
हालांकि, इमेज पर load
इवेंट (जिसे onload
भी कहा जाता है) ब्लॉक है: DevTools, onload
इवेंट की रिपोर्ट 335 मिलीसेकंड में देता है. याद रखें कि onload
इवेंट उस पॉइंट को मार्क करता है जहां पेज के लिए ज़रूरी सभी रिसॉर्स डाउनलोड और प्रोसेस हो चुके होते हैं. इस पॉइंट पर, ब्राउज़र में लोडिंग स्पिनर (वॉटरफ़ॉल में लाल वर्टिकल लाइन) घूमना बंद हो सकता है.
मिक्स में JavaScript और CSS जोड़ना
हमारा "Hello World experience" पेज सामान्य दिखता है, लेकिन इसमें बहुत कुछ होता है. असल में, हमें सिर्फ़ एचटीएमएल के अलावा और भी चीज़ों की ज़रूरत होगी: हो सकता है कि हमारे पास सीएसएस स्टाइल शीट और एक या उससे ज़्यादा स्क्रिप्ट हों, ताकि हम अपने पेज में कुछ इंटरैक्टिविटी जोड़ सकें. दोनों को मिक्स में जोड़कर देखें कि क्या होता है:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Script</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body onload="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="timing.js"></script>
</body>
</html>
JavaScript और सीएसएस जोड़ने से पहले:
JavaScript और सीएसएस की मदद से:
बाहरी सीएसएस और JavaScript फ़ाइलें जोड़ने से, हमारे वॉटरफ़ॉल में दो अतिरिक्त अनुरोध जुड़ जाते हैं. ब्राउज़र, इन सभी अनुरोधों को लगभग एक ही समय पर डिस्पैच करता है. हालांकि, ध्यान दें कि अब domContentLoaded
और onload
इवेंट के बीच समय का अंतर बहुत कम है.
क्या हुआ?
- हमारे सादे एचटीएमएल उदाहरण के विपरीत, हमें सीएसएसओएम बनाने के लिए सीएसएस फ़ाइल को फ़ेच और पार्स भी करना होगा. साथ ही, रेंडर ट्री बनाने के लिए, हमें डीओएम और सीएसएसओएम, दोनों की ज़रूरत होगी.
- पेज में पार्स करने से रोकने वाली JavaScript फ़ाइल भी शामिल है. इसलिए,
domContentLoaded
इवेंट तब तक ब्लॉक रहता है, जब तक सीएसएस फ़ाइल डाउनलोड और पार्स नहीं हो जाती: JavaScript, CSSOM से क्वेरी कर सकता है. इसलिए, JavaScript को लागू करने से पहले, हमें सीएसएस फ़ाइल को तब तक ब्लॉक करना होगा, जब तक वह डाउनलोड नहीं हो जाती.
अगर हम अपनी बाहरी स्क्रिप्ट को इनलाइन स्क्रिप्ट से बदल दें, तो क्या होगा? भले ही स्क्रिप्ट को सीधे पेज में इनलाइन किया गया हो, लेकिन ब्राउज़र तब तक इसे लागू नहीं कर सकता, जब तक सीएसएसओएम नहीं बन जाता. कम शब्दों में, इनलाइन किया गया JavaScript भी पार्सर ब्लॉकिंग है.
हालांकि, सीएसएस को ब्लॉक करने के बावजूद, क्या स्क्रिप्ट को इनलाइन करने से पेज तेज़ी से रेंडर होता है? इसे आज़माकर देखें कि क्या होता है.
बाहरी JavaScript:
इनलाइन JavaScript:
हम एक अनुरोध कम कर रहे हैं, लेकिन onload
और domContentLoaded
, दोनों का समय एक जैसा है. क्यों? हम जानते हैं कि JavaScript इनलाइन है या बाहरी, इससे कोई फ़र्क़ नहीं पड़ता. ऐसा इसलिए है, क्योंकि ब्राउज़र स्क्रिप्ट टैग को हिट करते ही उसे ब्लॉक कर देता है और CSSOM बनने तक इंतज़ार करता है. इसके अलावा, हमारे पहले उदाहरण में, ब्राउज़र सीएसएस और JavaScript, दोनों को एक साथ डाउनलोड करता है और वे लगभग एक ही समय में डाउनलोड हो जाते हैं. इस मामले में, JavaScript कोड को इनलाइन करने से हमें ज़्यादा मदद नहीं मिलती. हालांकि, पेज को तेज़ी से रेंडर करने के लिए कई रणनीतियां अपनाई जा सकती हैं.
सबसे पहले, याद रखें कि सभी इनलाइन स्क्रिप्ट, पार्स करने वाले टूल को ब्लॉक करती हैं. हालांकि, बाहरी स्क्रिप्ट के लिए, पार्स करने वाले टूल को अनब्लॉक करने के लिए async
एट्रिब्यूट जोड़ा जा सकता है. इनलाइन करने की सुविधा को पहले जैसा करें और फिर से कोशिश करें:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Async</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body onload="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script async src="timing.js"></script>
</body>
</html>
पार्सर को ब्लॉक करने वाला (बाहरी) JavaScript:
असाइन (बाहरी) JavaScript:
बहुत बेहतर! एचटीएमएल को पार्स करने के कुछ समय बाद, domContentLoaded
इवेंट ट्रिगर होता है. ब्राउज़र को पता होता है कि JavaScript को ब्लॉक नहीं करना है. साथ ही, पार्स करने से रोकने वाली कोई दूसरी स्क्रिप्ट न होने की वजह से, सीएसएसओएम का निर्माण भी साथ-साथ किया जा सकता है.
इसके अलावा, हम सीएसएस और JavaScript, दोनों को इनलाइन कर सकते थे:
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure Inlined</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<style>
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
</style>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script>
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
ध्यान दें कि domContentLoaded
का समय, पिछले उदाहरण में बताए गए समय के बराबर है. हमने अपने JavaScript को असाइन के तौर पर मार्क करने के बजाय, सीएसएस और JS, दोनों को पेज में इनलाइन किया है. इससे हमारा एचटीएमएल पेज काफ़ी बड़ा हो जाता है. हालांकि, इसका फ़ायदा यह है कि ब्राउज़र को किसी बाहरी रिसॉर्स को फ़ेच करने के लिए इंतज़ार नहीं करना पड़ता. पेज में ही सब कुछ मौजूद होता है.
जैसा कि आप देख सकते हैं, बहुत ही बुनियादी पेज के लिए भी, क्रिटिकल रेंडरिंग पाथ को ऑप्टिमाइज़ करना आसान नहीं है: हमें अलग-अलग रिसॉर्स के बीच के डिपेंडेंसी ग्राफ़ को समझना होगा. साथ ही, यह भी पता लगाना होगा कि कौनसे रिसॉर्स "ज़रूरी" हैं. इसके बाद, हमें पेज पर उन रिसॉर्स को शामिल करने के लिए, अलग-अलग रणनीतियों में से किसी एक को चुनना होगा. इस समस्या का कोई एक समाधान नहीं है. हर पेज अलग होता है. सबसे सही रणनीति तय करने के लिए, आपको भी इसी तरह की प्रोसेस अपनानी होगी.
हालांकि, हम यह देख सकते हैं कि क्या हम कुछ सामान्य परफ़ॉर्मेंस पैटर्न की पहचान कर सकते हैं.
परफ़ॉर्मेंस पैटर्न
सबसे आसान पेज में सिर्फ़ एचटीएमएल मार्कअप होता है. इसमें सीएसएस, JavaScript या दूसरे तरह के रिसॉर्स नहीं होते. इस पेज को रेंडर करने के लिए, ब्राउज़र को अनुरोध शुरू करना होगा, एचटीएमएल दस्तावेज़ के आने का इंतज़ार करना होगा, उसे पार्स करना होगा, डीओएम बनाना होगा, और फिर उसे स्क्रीन पर रेंडर करना होगा:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Critical Path: No Style</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
T0 और T1 के बीच का समय, नेटवर्क और सर्वर को प्रोसेस करने में लगने वाला समय दिखाता है. अगर एचटीएमएल फ़ाइल छोटी है, तो सबसे अच्छे मामले में, सिर्फ़ एक नेटवर्क राउंड ट्रिप से पूरा दस्तावेज़ फ़ेच हो जाता है. टीसीपी ट्रांसपोर्ट प्रोटोकॉल के काम करने के तरीके की वजह से, बड़ी फ़ाइलों को भेजने के लिए ज़्यादा राउंड ट्रिप की ज़रूरत पड़ सकती है. इस वजह से, सबसे अच्छे मामले में ऊपर दिए गए पेज में एक राउंड ट्रिप (कम से कम) क्रिटिकल रेंडरिंग पाथ है.
अब उसी पेज पर, बाहरी सीएसएस फ़ाइल का इस्तेमाल करके देखें:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
एचटीएमएल दस्तावेज़ को फ़ेच करने के लिए, हमें फिर से नेटवर्क राउंड ट्रिप करना पड़ता है. इसके बाद, वापस मिले मार्कअप से हमें पता चलता है कि हमें सीएसएस फ़ाइल भी चाहिए. इसका मतलब है कि स्क्रीन पर पेज को रेंडर करने से पहले, ब्राउज़र को सर्वर पर वापस जाना होगा और सीएसएस फ़ाइल लेनी होगी. इस वजह से, इस पेज को दिखाने से पहले, कम से कम दो बार अनुरोध भेजना पड़ता है. फिर से, सीएसएस फ़ाइल को कई राउंड ट्रिप लग सकते हैं. इसलिए, "कम से कम" पर ज़ोर दिया गया है.
क्रिटिकल रेंडरिंग पाथ के बारे में बताने के लिए, हम इन शब्दों का इस्तेमाल करते हैं:
- ज़रूरी रिसॉर्स: ऐसा रिसॉर्स जो पेज की शुरुआती रेंडरिंग को ब्लॉक कर सकता है.
- क्रिटिकल पाथ की लंबाई: राउंड ट्रिप की संख्या या सभी ज़रूरी संसाधनों को फ़ेच करने में लगने वाला कुल समय.
- ज़रूरी बाइट: पेज को पहली बार रेंडर करने के लिए ज़रूरी बाइट की कुल संख्या. यह सभी ज़रूरी रिसॉर्स के ट्रांसफ़र फ़ाइल साइज़ का कुल योग होता है. हमारे पहले उदाहरण में, एक एचटीएमएल पेज के साथ एक ही क्रिटिकल रिसॉर्स (एचटीएमएल दस्तावेज़) था. क्रिटिकल पाथ की लंबाई भी एक नेटवर्क राउंड ट्रिप के बराबर थी (यह मानते हुए कि फ़ाइल छोटी थी) और कुल क्रिटिकल बाइट, सिर्फ़ एचटीएमएल दस्तावेज़ के ट्रांसफ़र साइज़ के बराबर थे.
अब इसकी तुलना, पिछले एचटीएमएल और सीएसएस उदाहरण के क्रिटिकल पाथ की विशेषताओं से करें:
- 2 ज़रूरी संसाधन
- क्रिटिकल पाथ की कम से कम लंबाई के लिए, 2 या उससे ज़्यादा राउंड ट्रिप
- 9 केबी के अहम बाइट
रेंडर ट्री बनाने के लिए, हमें एचटीएमएल और सीएसएस, दोनों की ज़रूरत होती है. इस वजह से, एचटीएमएल और सीएसएस, दोनों ही ज़रूरी रिसॉर्स हैं: सीएसएस को सिर्फ़ तब फ़ेच किया जाता है, जब ब्राउज़र को एचटीएमएल दस्तावेज़ मिल जाता है. इसलिए, क्रिटिकल पाथ की लंबाई कम से कम दो राउंड ट्रिप होती है. दोनों संसाधनों में कुल 9 केबी के क्रिटिकल बाइट हैं.
अब मिक्स में एक और JavaScript फ़ाइल जोड़ें.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js"></script>
</body>
</html>
हमने app.js
जोड़ा है, जो पेज पर मौजूद एक बाहरी JavaScript एसेट और पार्स करने वाले टूल को ब्लॉक करने वाला (यानी कि अहम) रिसॉर्स, दोनों है. इससे भी बुरा यह है कि JavaScript फ़ाइल को चलाने के लिए, हमें CSSOM को ब्लॉक करना होगा और तब तक इंतज़ार करना होगा, जब तक वह डाउनलोड नहीं हो जाता. याद रखें कि JavaScript, CSSOM से क्वेरी कर सकता है. इसलिए, style.css
डाउनलोड होने और CSSOM बनने तक ब्राउज़र रुक जाता है.
हालांकि, अगर हम इस पेज के "नेटवर्क वॉटरफ़ॉल" को देखें, तो आपको पता चलेगा कि सीएसएस और JavaScript, दोनों के अनुरोध एक ही समय पर शुरू किए जाते हैं. ब्राउज़र को एचटीएमएल मिलता है, दोनों रिसॉर्स का पता चलता है, और दोनों अनुरोध शुरू किए जाते हैं. इस वजह से, पिछली इमेज में दिखाए गए पेज में, क्रिटिकल पाथ की ये विशेषताएं हैं:
- 3 ज़रूरी संसाधन
- क्रिटिकल पाथ की कम से कम लंबाई के लिए, 2 या उससे ज़्यादा राउंड ट्रिप
- 11 केबी के अहम बाइट
अब हमारे पास तीन ज़रूरी संसाधन हैं, जिनमें कुल 11 केबी के ज़रूरी बाइट हैं. हालांकि, हमारे क्रिटिकल पाथ की लंबाई अब भी दो राउंड ट्रिप है, क्योंकि हम सीएसएस और JavaScript को एक साथ ट्रांसफ़र कर सकते हैं. क्रिटिकल रेंडरिंग पाथ की विशेषताओं का पता लगाने का मतलब है कि ज़रूरी संसाधनों की पहचान की जा सकती है. साथ ही, यह भी समझा जा सकता है कि ब्राउज़र, फ़ेच करने की प्रोसेस को कैसे शेड्यूल करेगा.
अपनी साइट के डेवलपर से बातचीत करने के बाद, हमें पता चला कि हमारे पेज पर शामिल किए गए JavaScript को ब्लॉक करने की ज़रूरत नहीं है. हमारे पास कुछ आंकड़े और अन्य कोड हैं, जिन्हें हमारे पेज के रेंडर होने को ब्लॉक करने की ज़रूरत नहीं है. इस जानकारी के आधार पर, हम पार्सर को अनब्लॉक करने के लिए, <script>
एलिमेंट में async
एट्रिब्यूट जोड़ सकते हैं:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js" async></script>
</body>
</html>
असिंक्रोनस स्क्रिप्ट के कई फ़ायदे हैं:
- स्क्रिप्ट अब पार्स करने से नहीं रोकती और यह रेंडरिंग के अहम पाथ का हिस्सा नहीं है.
- कोई दूसरी ज़रूरी स्क्रिप्ट न होने की वजह से, सीएसएस को
domContentLoaded
इवेंट को ब्लॉक करने की ज़रूरत नहीं है. domContentLoaded
इवेंट जितनी जल्दी ट्रिगर होगा, ऐप्लिकेशन का अन्य लॉजिक उतनी ही जल्दी लागू हो पाएगा.
इस वजह से, हमारा ऑप्टिमाइज़ किया गया पेज अब दो ज़रूरी संसाधनों (एचटीएमएल और सीएसएस) पर वापस आ गया है. साथ ही, इस पेज के क्रिटिकल पाथ की लंबाई कम से कम दो राउंड ट्रिप है और इसमें कुल 9 केबी के क्रिटिकल बाइट हैं.
आखिर में, अगर सीएसएस स्टाइल शीट सिर्फ़ प्रिंट के लिए ज़रूरी थी, तो वह कैसी दिखेगी?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" media="print" />
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<script src="app.js" async></script>
</body>
</html>
style.css रिसॉर्स का इस्तेमाल सिर्फ़ प्रिंट के लिए किया जाता है. इसलिए, पेज को रेंडर करने के लिए ब्राउज़र को उस पर ब्लॉक करने की ज़रूरत नहीं होती. इसलिए, DOM का निर्माण पूरा होने के बाद, ब्राउज़र के पास पेज को रेंडर करने के लिए ज़रूरी जानकारी होती है. इस वजह से, इस पेज में सिर्फ़ एक क्रिटिकल रिसॉर्स (एचटीएमएल दस्तावेज़) है. साथ ही, रेंडरिंग के लिए क्रिटिकल पाथ की कम से कम लंबाई एक राउंड ट्रिप है.