تحليل أداء مسار العرض الحرج

تاريخ النشر: 31 آذار (مارس) 2014

يتطلّب تحديد نقاط الاختناق في أداء مسار التقديم المهم وحلّها معرفة جيدة بالأخطاء الشائعة. ستساعدك جولة إرشادية لتحديد أنماط الأداء الشائعة في تحسين صفحاتك.

من خلال تحسين مسار العرض المهم، يمكن للمتصفّح عرض الصفحة في أسرع وقت ممكن، ما يؤدي إلى زيادة التفاعل وعرض المزيد من الصفحات وتحسين الإحالات الناجحة. لتقليل الوقت الذي يقضيه الزائر في مشاهدة شاشة فارغة، علينا تحسين الموارد التي يتم تحميلها والترتيب الذي يتم تحميلها به.

للمساعدة في توضيح هذه العملية، ابدأ بأبسط حالة ممكنة وطوِّر صفحتنا تدريجيًا لتضمين موارد وأنماط ومنطق تطبيق إضافي. وخلال هذه العملية، سنحسِّن كل حالة، وسنحدِّد أيضًا المشاكل المحتملة.

حتى الآن، ركّزنا حصريًا على ما يحدث في المتصفّح بعد توفّر المورد (ملف CSS أو JS أو HTML) للمعالجة. لقد تجاهلنا الوقت الذي يستغرقه جلب المورد من ذاكرة التخزين المؤقت أو من الشبكة. سنفترض ما يلي:

  • تستغرق رحلة الذهاب والعودة للشبكة (وقت استجابة الانتشار) إلى الخادم 100 ملي ثانية.
  • وقت استجابة الخادم هو 100 ملي ثانية لمستند HTML و10 ملي ثانية لجميع الملفات الأخرى.

تجربة "مرحبًا بك"

<!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>

التجربة الآن

ابدأ باستخدام علامات HTML الأساسية وصورة واحدة، بدون استخدام CSS أو JavaScript. بعد ذلك، افتح لوحة "الشبكة" في "أدوات مطوّري البرامج في Chrome" وتحقّق من تدفق الموارد الناتج:

CRP

وكما هو متوقع، استغرق تنزيل ملف HTML حوالي 200 ملّي ثانية. يُرجى العِلم أنّ الجزء الشفاف من الخطّ الأزرق يمثّل المدة التي ينتظر فيها المتصفّح على الشبكة بدون تلقّي أي وحدات بايت من الاستجابة، في حين يعرض الجزء المُكتَمِل الوقت الذي يستغرقه إكمال عملية التنزيل بعد تلقّي وحدات البايت الأولى من الاستجابة. حجم تنزيل HTML صغير (أقل من 4K)، لذا كل ما نحتاج إليه هو جولة ذهاب وعودة واحدة لجلب الملف بالكامل. ونتيجة لذلك، يستغرق جلب مستند HTML حوالي 200 ملّي ثانية، وينتظر نصف الوقت الآخر في انتظار استجابة الخادم.

عندما يصبح محتوى HTML متاحًا، يحلّل المتصفّح وحدات البايت ويحوّلها إلى وحدات ترميز وينشئ شجرة نموذج كائن المستند (DOM). يُرجى ملاحظة أنّ "أدوات المطوّر" تسجِّل وقت حدث DOMContentLoaded في أسفل الصفحة (216 ملي ثانية) بشكل ملائم، وهو ما يتوافق أيضًا مع الخط العمودي الأزرق. الفجوة بين نهاية تنزيل HTML والخط العمودي الأزرق (DOMContentLoaded) هي الوقت الذي يستغرقه المتصفّح لإنشاء شجرة DOM، وفي هذه الحالة، لا تتجاوز بضع مللي ثوانٍ.

يُرجى العلم أنّ "صورتنا الرائعة" لم تحظر الحدث domContentLoaded. تبيّن لنا أنّه يمكننا إنشاء شجرة العرض وحتى عرض الصفحة بدون انتظار كل مادة عرض على الصفحة: ليست كل الموارد مهمة لتقديم سرعة عرض الصفحة الأولى. في الواقع، عندما نتحدث عن مسار العرض المهم، نقصد عادةً ترميز HTML وCSS وJavaScript. لا تحظر الصور العرض الأولي للصفحة، ولكن يجب أن نحاول عرض الصور في أسرع وقت ممكن.

ومع ذلك، تم حظر حدث load (المعروف أيضًا باسم onload) في الصورة: تُبلغ "أدوات مطوّري البرامج" عن حدث onload بعد 335 ملي ثانية. يُرجى تذكُّر أنّ الحدث onload يشير إلى النقطة التي تم فيها تنزيل كل الموارد التي تتطلّبها الصفحة ومعالجتها. وفي هذه المرحلة، يمكن أن يتوقف مؤشر التحميل في المتصفّح عن الدوران (الخطّ العمودي الأحمر في المخطّط البياني).

إضافة JavaScript وCSS إلى المحتوى

تبدو صفحة "مرحبًا بالعالم" أساسية، ولكن هناك الكثير من الإنجازات. من الناحية العملية، سنحتاج إلى أكثر من HTML فقط: فيحتمل أن يكون لدينا ورقة أنماط CSS ونص برمجي واحد أو أكثر لإضافة بعض التفاعل إلى صفحتنا. أضِف كلاهما إلى المحتوى لمعرفة النتيجة:

<!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 وCSS:

CRP في DOM

باستخدام JavaScript وCSS:

DOM وCSSOM وJS

تؤدي إضافة ملفات CSS وJavaScript الخارجية إلى إضافة طلبَين إضافيَين إلى العرض المعروض، ويرسل المتصفّح جميع هذه الطلبات في الوقت نفسه تقريبًا. ومع ذلك، يُرجى العِلم أنّ هناك الآن فرقًا زمنيًا أصغر بكثير بين حدثَي domContentLoaded وonload.

ما السبب؟

  • على عكس مثال HTML العادي، نحتاج أيضًا إلى جلب ملف CSS وتحليله لإنشاء CSSOM، ونحتاج إلى كل من DOM وCSSOM لإنشاء شجرة العرض.
  • بما أنّ الصفحة تحتوي أيضًا على ملف JavaScript يحظر المُحلِّل، يتم حظر الحدث domContentLoaded إلى أن يتم تنزيل ملف CSS وتحليله: لأنّ JavaScript قد يطلب بيانات من CSSOM، يجب حظر ملف CSS إلى أن يتم تنزيله قبل أن نتمكّن من تنفيذ JavaScript.

ماذا لو استبدلنا النص البرمجي الخارجي بنص برمجي مضمّن؟ حتى إذا كان النص البرمجي مضمّنًا في الصفحة مباشرةً، لا يمكن للمتصفح تنفيذه إلا بعد إنشاء CSSOM. باختصار، تعمل لغة JavaScript المضمّنة على حظر المحلل اللغوي أيضًا.

ومع ذلك، على الرغم من الحظر على CSS، هل يؤدي تضمين النص البرمجي إلى عرض الصفحة بشكل أسرع؟ جرِّب ذلك وراقِب النتائج.

JavaScript الخارجية:

DOM وCSSOM وJS

JavaScript المضمّنة:

نموذج DOM وCSSOM وJavaScript المضمّن

سنقدّم طلبًا واحدًا أقل، ولكنّ وقتَي onload وdomContentLoaded متطابقان بشكل أساسي. لماذا؟ نعلم أنّه لا يهمّ ما إذا كان JavaScript مضمّنًا أو خارجيًا، لأنّه بمجرد أن يصل المتصفّح إلى علامة النص البرمجي، يتم حظره وينتظر إلى أن يتم إنشاء CSSOM. بالإضافة إلى ذلك، في المثال الأول، ينزِّل المتصفّح كلّ من CSS و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 (الخارجية) التي تحظر المُحلِّل:

DOM، CSSOM، JS

JavaScript غير المتزامنة (الخارجية):

نموذج DOM وCSSOM وJavaScript غير المتزامن

أفضل بكثير. يتم تشغيل الحدث domContentLoaded بعد وقت قصير من تحليل HTML، ويعرف المتصفّح عدم حظر JavaScript، وبما أنّه لا تتوفّر نصوص برمجية أخرى تحظر التحليل، يمكن أيضًا مواصلة إنشاء CSSOM بشكل متزامن.

بدلاً من ذلك، يمكننا تضمين كلّ من CSS و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>

التجربة الآن

نموذج DOM وCSS المضمّن وJavaScript المضمّن

يُرجى ملاحظة أنّ وقت domContentLoaded هو نفسه في المثال السابق، ولكن بدلاً من وضع علامة على JavaScript على أنّه غير متزامن، أضفنا كلّ من CSS وJS إلى الصفحة نفسها. يؤدي ذلك إلى زيادة حجم صفحة HTML بشكل كبير، ولكن الجانب الإيجابي هو أنّ المتصفّح لا يحتاج إلى الانتظار لجلب أي موارد خارجية، فكل شيء متوفّر في الصفحة.

كما يمكنك أن ترى، حتى مع استخدام صفحة أساسية جدًا، فإنّ تحسين مسار العرض المهمّ ليس عملية بسيطة: علينا فهم الرسم البياني للتبعية بين الموارد المختلفة، وتحديد الموارد "المهمة"، واختيار استراتيجية من بين الاستراتيجيات المختلفة لكيفية تضمين هذه الموارد في الصفحة. ليس هناك حل واحد لهذه المشكلة، فكل صفحة تختلف عن الأخرى. عليك اتّباع عملية مماثلة بنفسك لمعرفة الاستراتيجية المثلى.

مع ذلك، تأكَّد مما إذا كان بإمكاننا التراجع وتحديد بعض أنماط الأداء العامة.

أنماط الأداء

تتألف أبسط صفحة ممكنة من ترميز HTML فقط، بدون CSS أو JavaScript أو أنواع أخرى من الموارد. لعرض هذه الصفحة، على المتصفّح بدء الطلب، والانتظار حتى يصل مستند HTML، وتحليله، وإنشاء عنصر DOM، ثم عرضه أخيرًا على الشاشة:

<!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>

التجربة الآن

مرحبًا بالعالم CRP

يشير الوقت بين T0 وT1 إلى أوقات معالجة الشبكة والخادم. في أفضل الأحوال (إذا كان ملف HTML صغيرًا)، يمكن جلب المستند بأكمله من خلال رحلة واحدة فقط على الشبكة. بسبب طريقة عمل بروتوكولات النقل في بروتوكول TCP، قد تتطلّب الملفات الأكبر حجمًا المزيد من عمليات النقل ذهابًا وإيابًا. نتيجةً لذلك، في أفضل الأحوال، تحتوي الصفحة أعلاه على مسار عرض مهم يتضمن رحلة ذهاب وإياب واحدة (بحد أدنى).

لنلقِ نظرة الآن على الصفحة نفسها، ولكن مع ملف CSS خارجي:

<!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>

التجربة

معالجة مهام DOM + CSSOM

ومرة أخرى، نتحمل تكاليف ذهاب وعودة للشبكة لجلب مستند HTML، ثم يخبرنا الترميز الذي تم استرداده أننا نحتاج أيضًا إلى ملف CSS؛ وهذا يعني أن المتصفح يجب أن يعود إلى الخادم ويحصل على CSS قبل أن يتمكن من عرض الصفحة على الشاشة. نتيجةً لذلك، تتطلّب هذه الصفحة إجراء عمليتين ذهابًا وإيابًا على الأقل قبل أن يتم عرضها. مرة أخرى، قد يستغرق ملف CSS عدة عمليات ذهاب وإياب، وبالتالي التركيز على "الحد الأدنى".

في ما يلي بعض المصطلحات التي نستخدمها لوصف مسار العرض الحرج:

  • المورد المهم: هو المورد الذي يمكن أن يؤدي إلى حظر العرض الأوّلي للصفحة.
  • طول المسار الحرج: عدد عمليات التنقّل ذهابًا وإيابًا، أو إجمالي الوقت المطلوب لجلب جميع الموارد الحرجة
  • وحدات البايت المهمة: إجمالي عدد وحدات البايت المطلوبة للوصول إلى العرض الأول للصفحة، وهو مجموع أحجام ملفات النقل لجميع الموارد المهمة. في المثال الأول الذي يتضمّن صفحة HTML واحدة، كان هناك مورد مهم واحد (مستند HTML)، وكان طول المسار المهم أيضًا مساويًا لرحلة ذهاب وإياب واحدة على الشبكة (على افتراض أنّ الملف صغير)، وكان إجمالي عدد البايتات المهمة هو حجم نقل مستند HTML نفسه فقط.

قارِن ذلك الآن بخصائص المسار الحرج في مثال HTML وCSS السابق:

DOM + CSSOM CRP

  • موردَان مهمّان
  • عمليتان أو أكثر من تنقّلات ذهاباً وإيابًا للحد الأدنى لطول المسار الحرج
  • 9 كيلوبايت من البايتات المهمة

نحتاج إلى HTML وCSS لإنشاء شجرة العرض. نتيجةً لذلك، يُعدّ كلّ من HTML وCSS موردَين مهمّين: لا يتمّ جلب CSS إلا بعد أن يحصل المتصفّح على مستند HTML، وبالتالي يبلغ طول المسار الحرج جولتين على الأقل. يصل حجم كلا الموردين إلى 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 والانتظار إلى أن يتم تنزيل style.css وإنشاء CSSOM. يُرجى تذكُّر أنّ JavaScript يمكنه طلب بيانات من CSSOM، وبالتالي يتوقف المتصفّح مؤقتًا إلى أن يتم تنزيل style.css وإنشاء CSSOM.

DOM وCSSOM وJavaScript CRP

ومع ذلك، من الناحية العملية، إذا اطّلعنا على "العرض المرئي للشبكة" لهذه الصفحة، ستلاحظ أنّه يتم بدء طلبَي CSS وJavaScript في الوقت نفسه تقريبًا، ويحصل المتصفّح على ملف HTML، ويرصد كلا الموردَين، ويُطلق كلا الطلبَين. ونتيجةً لذلك، فإنّ الصفحة المعروضة في الصورة السابقة لها خصائص المسار الحرج التالية:

  • 3 موارد مهمة
  • عمليتان أو أكثر من تنقّلات ذهاباً وإيابًا للحد الأدنى لطول المسار الحرج
  • 11 كيلوبايت من وحدات البايت الحرجة

لدينا الآن ثلاثة موارد مهمة تبلغ مجموعها 11 كيلوبايت من البايتات المهمة، ولكن لا يزال طول المسار الحرج هو جولتان لأنّه يمكننا نقل CSS وJavaScript بشكل موازٍ. إنّ معرفة خصائص مسار المعالجة الحرج يعني أنّه يمكنك تحديد الموارد الحرجة وفهم كيفية جدولة المتصفّح لعمليات جلبها.

بعد التواصل مع مطوّري الموقع الإلكتروني، تبيّن لنا أنّه ليس من الضروري حظر JavaScript الذي أدرجناه في صفحتنا، لأنّنا نستخدم بعض الإحصاءات والرموز البرمجية الأخرى التي لا تحتاج إلى حظر عرض صفحتنا. بعد الحصول على المعلومات المطلوبة، يمكننا إضافة السمة async إلى العنصر <script> لإزالة حظر المحلل اللغوي:

<!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>

التجربة

تحليل DOM وCSSOM وJavaScript غير المتزامن

هناك عدة مزايا للنص البرمجي غير المتزامن:

  • لم يعد النص البرمجي يحظر المحلل اللغوي وليس جزءًا من مسار العرض الحرج.
  • ولأنّه لا تتوفّر نصوص برمجية أخرى مهمة، لا تحتاج CSS إلى حظر الحدث domContentLoaded.
  • وكلما كان بدء الحدث domContentLoaded أسرع، كان بإمكان منطق التطبيق الآخر بدء التنفيذ بشكل أسرع.

نتيجةً لذلك، عادت صفحتنا المحسّنة الآن إلى موردَين مهمّين (HTML وCSS)، مع الحد الأدنى لطول المسار المهمّ الذي يتطلّب رحلتَي ذهاب وإياب، وإجمالي 9 كيلوبايت من وحدات البايت المهمة.

أخيرًا، إذا كانت ورقة أنماط CSS مطلوبة للطباعة فقط، كيف ستبدو؟

<!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>

التجربة الآن

نموذج العناصر في المستند (DOM) وCSS غير المحظورة وبرنامج JavaScript CRP غير المتزامن

بما أنّ مورد style.css يُستخدم للطباعة فقط، لا يحتاج المتصفّح إلى حظره لعرض الصفحة. وبالتالي، فور اكتمال إنشاء نموذج العناصر في المستند (DOM)، تكون لدى المتصفّح معلومات كافية لعرض الصفحة. ونتيجةً لذلك، تحتوي هذه الصفحة على مورد مهم واحد فقط (مستند HTML)، ويكون الحد الأدنى لطول مسار العرض الحرج هو رحلة ذهاب وعودة واحدة.

ملاحظات