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

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

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

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

لقد ركّزنا حتى الآن على ما يحدث في المتصفِّح بعد إتاحة الموارد (ملف 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 إلى المزيج

تبدو صفحة "Hello World" (تجربة مرحبًا بالعالم) بسيطة، إلا أنَّ الكثير منها ينطوي على مزيد من التفاصيل. من الناحية العملية، سنحتاج إلى عناصر أخرى غير 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.

What happened?

  • على عكس مثال 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 كثيرًا. هناك العديد من الاستراتيجيات التي يمكن أن تؤدي إلى عرض الصفحات بشكل أسرع.

أولاً، تذكّر أنّ جميع النصوص البرمجية المضمّنة تحظر المحلل اللغوي، ولكن بالنسبة إلى النصوص البرمجية الخارجية، يمكننا إضافة الكلمة الرئيسية "غير متزامنة" لإلغاء حظر المحلل اللغوي. لنتراجع عن ذلك ونجرب ذلك:

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

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

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

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

لنقارن ذلك الآن بخصائص المسار الحرج في مثال HTML + CSS أعلاه:

DOM + CSSOM CRP

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

DOM وCSSOM وJavaScript CRP

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

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

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

بعد الدردشة مع مطوري المواقع الإلكترونية، أدركنا أنّ JavaScript التي ضمّنناها في صفحتنا لا يلزم أن يتم حظره، فلدينا بعض الإحصاءات والرموز الأخرى التي لا تحتاج إلى حظر عرض الصفحة. وباستخدام هذه المعلومات، يمكننا إضافة السمة "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>

التجربة الآن

DOM وCSSOM وCRP غير متزامن ل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 التي لا تمنع الوصول وسياسة CRP غير المتزامنة في JavaScript

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

إضافة ملاحظات