قياس مقاييس الأداء المهمّة باستخدام "إحصاءات Google"

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

تُعد أدوات مثل WebPagetest.org بداية رائعة لتحسينات الأداء، ولكن الاختبار الحقيقي لأداء الموقع سيكون دائمًا بيانات حقيقية من المستخدمين الفعليين.

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

ما ستتعرَّف عليه

  • كيفية قياس مقاييس الأداء بدقة وفعالية باستخدام واجهة برمجة تطبيقات أوقات المستخدم
  • كيفية إرسال تلك البيانات إلى "إحصاءات Google" حتى يتم إدراجها في تقاريرك

الأشياء التي تحتاج إليها

كيف ستستخدم هذا البرنامج التعليمي؟

قراءة القراءة فقط قراءة القراءة وإكمال التدريبات

كيف تقيّم تجربة إنشاء مواقع إلكترونية أو تطبيقات؟

مبتدئ متوسط محترف

يمكنك إما تنزيل كل نماذج الرمز على جهاز الكمبيوتر...

تنزيل ملف Zip

...أو استنساخ مستودع GitHub من سطر الأوامر.

git clone https://github.com/googlecodelabs/performance-analytics.git

يتم تقسيم نموذج الرمز إلى أدلة فرعية تتوافق مع كل خطوة من الخطوات المرقمة في هذا الدرس التطبيقي حول الترميز. ويمكنك استخدام هذا الخيار بسهولة للتخطّي في مختبَر الترميز أو التحقّق من صحة التنفيذ.

إذا كان بإمكانك الوصول إلى برنامج اختلافات، يمكنك استخدامه لمعرفة ما تغير بالضبط من خطوة إلى أخرى.

في هذا الدرس التطبيقي حول الترميز، ستأخذ ملف HTML واحدًا يحمّل مواد العرض التالية:

  • خطوط الويب
  • أوراق الأنماط
  • الصور
  • JavaScript

وستكتب رمزًا جديدًا يقيس مقاييس الأداء الرئيسية لكل نوع من أنواع مواد العرض هذه.

اعتبارات أداء مواد العرض

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

صفحات الأنماط المتتالية (CSS)

على سبيل المثال، تحظر أوراق الأنماط عرض جميع العناصر في نموذج العناصر في المستند (DOM) التي تأتي بعدها، ما يعني أنّه على المتصفِّح إرسال طلب إلى ورقة الأنماط، وتنزيلها، ثم تحليلها قبل أن تتمكن من عرض أي محتوى في DOM الذي يأتي بعده. لهذا السبب، من الأفضل عادةً وضع أوراق الأنماط في <head> داخل المستند. ونظرًا إلى طبيعة حظر CSS، غالبًا ما ننصح أيضًا بوضع CSS المهمة فقط في <head&gt؛ وتحميل خدمة CSS غير المهمة بشكل غير متزامن بعد ذلك.

JavaScript

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

ولهذا السبب، غالبًا ما ننصح بتحميل JavaScript مباشرةً قبل علامة الإغلاق &lt//body>، بحيث يتوفّر معظم عناصر DOM في أسرع وقت ممكن.

خطوط الويب

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

الصور

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

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

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

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Performance Analytics Demo</title>

  <!-- Start fonts -->
  <link href="https://fonts.googleapis.com/css?family=Roboto:400,700,400italic" rel="stylesheet">
  <!-- End fonts -->

  <!-- Start CSS -->
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  <style>
    body { font-family: Roboto, sans-serif; margin: 1em; }
    img { float: left; height: auto; width: 33.33%; }
    .gallery { overflow: hidden; }
  </style>
  <!-- End CSS -->

</head>
<body>

  <div class="container">

    <!-- Start images -->
    <div class="gallery">
      <img src="http://lorempixel.com/380/200/animals/1/">
      <img src="http://lorempixel.com/380/200/animals/2/">
      <img src="http://lorempixel.com/380/200/animals/3/">
    </div>
    <!-- End images -->

    <h1>Performance Analytics Demo</h1>
    <p>Real performance data from real users.</p>

  </div>

  <!-- Start JavaScript -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  <!-- End JavaScript -->

</body>
</html>

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

لقطة شاشة يوم 11-05-2016 في الساعة 1.03.43 مساءً.png

من المفترض أن يكون بإمكانك الآن الانتقال إلى http://127.0.0.1:8887/ في المتصفّح والاطّلاع على الملف التجريبي. من المفترض أن تظهر بشكلٍ مشابه لما يلي:

لقطة شاشة يوم 11-05-2016 في الساعة 10.59.03 صباحًا.png

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

كما هو موضّح في القسم "اعتبارات أداء مواد العرض"، سيحظر CSS عرض عناصر DOM وكذلك تنفيذ النصوص البرمجية التي تأتي بعده في DOM.

يحتوي الملف التجريبي الذي أنشأته للتو على خدمة CSS التالية التي تشير إلى Bootstrap وبعض الأنماط المضمّنة.

<!-- Start CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<style>
  body { font-family: Roboto, sans-serif; margin: 1em; }
  img { float: left; height: auto; width: 33.33%; }
  .gallery { overflow: hidden; }
</style>
<!-- End CSS -->

وبما أنّ CSS تحظر كلاً من عرض عناصر DOM وتنفيذ النصوص البرمجية، من الممكن تحديد وقت انتهاء CSS من خلال إضافة علامة <script> بعد علامة CSS التي تخزّن الوقت الحالي مباشرةً.

يمكنك إجراء ذلك من خلال إنشاء متغيّر وتخصيص new Date() له، ولكن باستخدام User Timing API، هناك طريقة أسهل بكثير: طريقة performance.mark.

للإشارة إلى وقت انتهاء خدمة مقارنة الأسعار (CSS) من حظر العرض وتنفيذ النص البرمجي، أضِف سطر الرمز التالي مباشرةً قبل تعليق الإغلاق <!-- End CSS -->.

<script>performance.mark('css:unblock');</script>

تنشئ الطريقة performance.mark طابعًا زمنيًا بدقة عالية في هذه المرحلة الزمنية، وتربطه بأي اسم تم تمريره إلى الطريقة. في هذه الحالة، أعدت تسمية العلامة "css:unblock".

تُستخدم طريقة performance.mark يدويًا باستخدام طريقة performance.measure، التي تُستخدم لحساب فرق الوقت بين علامتين (بالإضافة إلى العلامات التي تنشئها، يمكنك أيضًا استخدام العلامات التي ينشئها المتصفح تلقائيًا للنقاط المختلفة في واجهة برمجة تطبيقات توقيت التنقل).

تقيس دالة الأداة التالية المدة وتعرض الفترة الزمنية بين علامة تمت إضافتها وعلامة responseEnd تم إنشاؤها بواسطة واجهة برمجة تطبيقات توقيت التنقل.

function measureDuration(mark, opt_reference) {
  var reference = opt_reference || 'responseEnd';
  var name = reference + ':' + mark;

  // Clears any existing measurements with the same name.
  performance.clearMeasures(name);

  // Creates a new measurement from the reference point to the specified mark.
  // If more than one mark with this name exists, the most recent one is used.
  performance.measure(name, reference, mark);

  // Gets the value of the measurement just created.
  var measure = performance.getEntriesByName(name)[0];

  // Returns the measure duration.
  return measure.duration;
}

لبدء استخدام دالة الأداة هذه، أنشئ ملفًا جديدًا باسم perf-analytics.js (في الدليل نفسه لملف index.html) وانسخ الرمز أعلاه والصقه في ذلك الملف.

الآن بعد أن تم تحديد هذه الدالة، يمكنك استدعاءها وتمريرها باسم "&quot؛css:unblock". لمنع التداخل مع أي تحميل آخر للموارد، يجب تأجيل تنفيذ هذه القياسات حتى بعد إطلاق أحداث تحميل النافذة.

بعد كتابة دالة لاستدعاء هذا الرمز، يجب أن يظهر ملف perf-analytics.js على النحو التالي:

window.onload = function() {
  measureCssUnblockTime();
};


/**
 * Calculates the time duration between the responseEnd timing event and when
 * the CSS stops blocking rendering, then logs that value to the console.
 */
function measureCssUnblockTime() {
  console.log('CSS', 'unblock', measureDuration('css:unblock'));
}


/**
 * Accepts a mark name and an optional reference point in the navigation timing
 * API and returns the time duration between the reference point and the last
 * mark (chronologically).
 * @param {string} mark The mark name.
 * @param {string=} opt_reference An optional reference point from the
 *     navigation timing API. Defaults to 'responseEnd'.
 * @return {number} The time duration
 */
function measureDuration(mark, opt_reference) {
  var reference = opt_reference || 'responseEnd';
  var name = reference + ':' + mark;

  // Clears any existing measurements with the same name.
  performance.clearMeasures(name);

  // Creates a new measurement from the reference point to the specified mark.
  // If more than one mark with this name exists, the most recent one is used.
  performance.measure(name, reference, mark);

  // Gets the value of the measurement just created.
  var measure = performance.getEntriesByName(name)[0];

  // Returns the measure duration.
  return measure.duration;
}

أخيرًا، يجب تحميل النص البرمجي perf-analytics.js من index.html. ولإجراء ذلك، أضِف علامة النص البرمجي التالية إلى المستند الرئيسي. تأكد من إضافته في النهاية حتي لا يتداخل مع تحميل موارد أخرى.

<!-- Start performance analytics -->
<script async src="perf-analytics.js"></script>
<!-- End performance analytics -->

بعد الانتهاء من هذه الخطوة، يجب أن يتطابق الرمز البرمجي مع الرموز المضمّنة في دليل 01-css الخاص بمستودع الدرس التطبيقي للرمز.

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

لقطة شاشة يوم 17-05-2016 في الساعة 11.13.02 صباحًا

يتم عادةً تحميل خطوط الويب من خلال ورقة أنماط خارجية، كما هو موضح في الملف التجريبي الأولي:

<!-- Start fonts -->
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700,400italic" rel="stylesheet">
<!-- End fonts -->

وبما أنّ هذه العلامة <link> في ملف CSS، قد يبدو أنّ عملية تحديد الخطوط جاهزة للتحميل وجاهزة للاستخدام، مثل إضافة علامة داخل علامة <script> بعد <link> مباشرةً، تمامًا كما في الخطوة 1.

الأمر ليس سهلاً.

تحظر أوراق الأنماط تنفيذ JavaScript بسبب استخدام محتوى أوراق الأنماط لإنشاء CSSOM، وبما أنّ JavaScript التي يتم تحميلها تحتاج إلى الوصول إلى CSSOM، يجب أن يتأخر التنفيذ إلى أن يتم إنشاء CSSOM بالكامل.

ملاحظة: إنّ المتصفّح يمكنه إنشاء CSSOM بدون تنزيل الخط، ما يعني أنه في حال إضافة علامة باستخدام علامة نص برمجي مضمّنة في DOM مباشرةً بعد علامة font'ssheet <link> العلامة، من المحتمل أن تحدث العلامة قبل تحميل الخط بالكامل.

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

يمكن تحميل معظم خطوط الويب (بما في ذلك خطوط Google وtypekit وfont.com) عبر النص البرمجي webfont.js الذي طوّرته Google وTypekit.

لتحديث المستند الرئيسي لاستخدام webfont.js لتحميل الخطوط (بدلاً من علامة <link>)، عليك استبدال قسم الخطوط في الرمز بما يلي:

<!-- Start fonts -->
<script>
window.WebFontConfig = {
  google: {families: ['Roboto:400,700,400italic']},
  timeout: 10000,
  active: function() {
    performance.mark('fonts:active');
  }
};
</script>
<script async src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
<!-- End fonts -->

هناك أمران مهمان يجب ملاحظتهما في الرمز أعلاه:

  • تنشئ هذه الأداة علامة ""fonts:active" في معاودة الاتصال النشطة، بحيث يمكنك لاحقًا قياس المدة التي استغرقها تحميل الخطوط.
  • تحتوي العلامة <script> التي تحمّل webfonts.js على السمة async، لذلك لن تمنع تحليل أو عرض بقية المستند (لا ينطبق ذلك على علامات <link>).

على الرغم من أن الرموز الواردة أعلاه تنشئ علامة &&;fonts:active" علامة;، فإن قياس هذه العلامة وتسجيلها في وحدة التحكم ليس سهلاً كما هو الحال مع العلامة "css:unblock". والسبب في ذلك هو أن تحميل الخطوط يحدث الآن بشكل غير متزامن، لذلك إذا حاولت قياس علامة "fonts:active" في معالج window.onload (كما فعلت مع "css:unblock")، سيصبح من الصعب جدًا تحميل الخط بعد ذلك.

ولحل هذه المشكلة، يمكنك إنشاء وعود يتم حله بعد تحميل الخط. تنفّذ الدالة التالية ذلك نيابةً عنك. انسخه والصقه في ملف Perf-analytics.js:

/**
 * Creates a promise that is resolved once the web fonts are fully load or
 * is reject if the fonts fail to load. The resolved callback calculates the
 * time duration between the responseEnd timing event and when the web fonts
 * are downloaded and active. If an error occurs loading the font, this fact
 * is logged to the console.
 */
function measureWebfontPerfAndFailures() {
  new Promise(function(resolve, reject) {
    // The classes `wf-active` or `wf-inactive` are added to the <html>
    // element once the fonts are loaded (or error).
    var loaded = /wf-(in)?active/.exec(document.documentElement.className);
    var success = loaded && !loaded[1]; // No "in" in the capture group.
    // If the fonts are already done loading, resolve immediately.
    // Otherwise resolve/reject in the active/inactive callbacks, respectively.
    if (loaded) {
      success ? resolve() : reject();
    }
    else {
      var originalAciveCallback = WebFontConfig.active;
      WebFontConfig.inactive = reject;
      WebFontConfig.active = function() {
        originalAciveCallback();
        resolve();
      };
      // In case the webfont.js script fails to load, always reject the
      // promise after the timeout amount.
      setTimeout(reject, WebFontConfig.timeout);
    }
  })
  .then(function() {
    console.log('Fonts', 'active', measureDuration('fonts:active'));
  })
  .catch(function() {
    console.error('Error loading web fonts')
  });
}

عليك أيضًا تعديل معالج window.onload لاستدعاء هذه الدالة الجديدة.

window.onload = function() {
  measureCssUnblockTime();
  measureWebfontPerfAndFailures();
};

بعد الانتهاء من هذه الخطوة، يجب أن يتطابق الرمز البرمجي مع الرموز المضمّنة في دليل 02-fonts الخاص بمستودع الدرس التطبيقي للرمز.

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

لقطة شاشة يوم 2016-05-17 الساعة 11.13.22 صباحًا.png

ليس من السهل معرفة عندما تكون الصورة مرئية كما قد تظهر لك. أنت تعلم من الخطوات السابقة أن أوراق الأنماط وعلامات <script> المتزامنة يمكن أن تحظر العرض والتحليل وتنفيذ النص البرمجي. ما لا تعرفه هو أنّ أيًا منهما لا يحظر فحص المُسبق الخاص بالمتصفّح.

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

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

عند تنزيل صورة قبل إضافتها إلى نموذج كائن المستند (DOM)، تكون النقطة التي تصبح فيها مرئية هي النقطة التي تكون فيها الصورة في DOM. في المقابل، إذا لم يتم تنزيل صورة قبل إضافتها إلى DOM، تصبح النقطة التي تصبح مرئية عند تنشيط معالج onload.

لذلك، حتى تعرف ما إذا كانت الصورة مرئية، يجب التعامل مع كلتا الحالتين.

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

لإضافة علامات لكل من وقت تحميل الصور ووقت عرضها، عدِّل رمز الصور في index.html على النحو التالي:

<!-- Start images -->
<div class="gallery">
  <img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
  <img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
  <img onload="performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
</div>
<script>performance.mark('img:visible')</script>
<!-- End images -->

بما أنّ الطريقة performance.measure لاسم علامة معيّنة ستستخدم دائمًا العلامة الأخيرة (إذا عثر على علامات متعددة تحمل الاسم نفسه)، يمكن استخدام دالة الأداة measureDuration في الملف perf-analytics.js لإجراء ذلك بدون أي تعديلات إضافية:

/**
 * Calculates the time duration between the responseEnd timing event and when
 * all images are loaded and visible on the page, then logs that value to the
 * console.
 */
function measureImagesVisibleTime() {
  console.log('Images', 'visible', measureDuration('img:visible'));
}

أضِف الدالة أعلاه إلى ملف perf-analytics.js، ثم عدِّل معالج window.onload لاستدعاءها:

window.onload = function() {
  measureCssBlockTime();
  measureWebfontPerfAndFailures();
  measureImagesVisibleTime();
};

بعد الانتهاء من هذه الخطوة، يجب أن يتطابق الرمز البرمجي مع الرموز المضمّنة في دليل 03-images الخاص بمستودع الدرس التطبيقي للرمز.

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

لقطة شاشة يوم 2016-05-17 الساعة 11.13.39 صباحًا

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

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

لتتبّع تحميل كل JavaScript وتنفيذها في المستند الرئيسي، عدِّل قسم JavaScript في index.html باستخدام الرمز التالي:

<!-- Start JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>performance.mark('js:execute');</script>
<!-- End JavaScript -->

سيؤدي هذا إلى إضافة علامة اسمها "js:execute" مباشرةً بعد تنزيل النصوص البرمجية لكل من jQuery وboostrap's الإضافية وإنهاء تنفيذها.

لقياس المدة المستغرقة، أضِف الدالة التالية إلى perf-analytics.js:

/**
 * Calculates the time duration between the responseEnd timing event and when
 * all synchronous JavaScript files have been downloaded and executed, then
 * logs that value to the console.
 */
function measureJavaSciptExecutionTime() {
  console.log('JavaScript', 'execute', measureDuration('js:execute'));
}

وبعد ذلك، يجب استدعاءها من المعالج window.onload:

window.onload = function() {
  measureCssBlockTime();
  measureWebfontPerfAndFailures();
  measureImagesVisibleTime();
  measureJavaSciptExecutionTime();
};

بعد الانتهاء من هذه الخطوة، يجب أن يتطابق الرمز البرمجي مع الرموز المضمّنة في دليل 04-javascript الخاص بمستودع الدرس التطبيقي للرمز.

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

لقطة شاشة يوم 17-05-2016 في الساعة 11.14.03 صباحًا.png

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

يمكنك استخدام ميزة اكتشاف الميزات لحل هذه المشكلة. أضِف جزء الرمز التالي مباشرةً قبل قسم الخطوط. يكتشف سطر JavaScript هذا دعم الطريقة performance.mark، لذا يجب إضافته إلى الصفحة قبل استخدام هذه الطريقة على الإطلاق:

<!-- Start feature detects -->
<script>window.__perf = window.performance && performance.mark;</script>
<!-- End feature detects -->

بعد ذلك، في أي مكان في index.html يمكنك فيه الاتصال بـ performance.mark، يمكنك وضع البادئة لميزة اكتشاف الميزة. في ما يلي مثال يوضح تحديث الرمز في جزء الصورة، ولكن عليك التأكُّد من تحديث الأقسام الأخرى أيضًا.

<!-- Start images -->
<div class="gallery">
  <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
  <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
  <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
</div>
<script>__perf && performance.mark('img:visible')</script>
<!-- End images -->

الآن بعد ضبط متغيّر __perf على window، يمكنك أيضًا استخدامه في perf-analytics.js للتأكّد من أنك لا تستخدم طريقة غير متوافقة في المتصفّح الحالي.

يجب تحديث الدالة measureDuration لإضافة الشرط الشرطي التالي:

function measureDuration(mark, opt_reference) {
  if (window.__perf) {
    // ...
  }
}

وأخيرًا، نظرًا لعدم توافق جميع المتصفحات مع وعود JavaScript، يجب أيضًا تضمين الدالة measureWebfontPerfAndFailures في شرط مشروط:

function measureWebfontPerfAndFailures() {
  if (window.Promise) {
    // ...
  }
}

من المفترض أن يكون بإمكانك الآن تشغيل الرمز في أي متصفح بدون مشاكل.

بعد الانتهاء من هذه الخطوة، يجب أن يتطابق الرمز البرمجي مع الرموز المضمّنة في دليل 05-feature-detects الخاص بمستودع الدرس التطبيقي للرمز.

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

أضِف الرمز التالي إلى index.html بعد كتلة JavaScript الرئيسية ولكن قبل تحميل النص البرمجي perf-analytics.js:

<!-- Start analytics tracking snippet -->
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics_debug.js"></script>
<!-- End analytics tracking snippet -->

إذا سبق لك إضافة "إحصاءات Google" إلى موقع إلكتروني، ستعرف أنه يجب عليك استبدال العنصر النائب "UA-XXXXX-Y" برقم تعريف التتبع الذي تلقيته عند إنشاء موقع جديد في "إحصاءات Google".

ينفّذ مقتطف التتبع في analytics.js أربعة أمور رئيسية:

  • إنشاء عنصر <script> غير متزامن يعمل على تنزيل مكتبة JavaScript analytics.js.
  • يؤدي هذا الإعداد إلى إعداد دالة ga() عامة (تُسمى قائمة انتظار أوامر ga()) تسمح لك بجدولة الأوامر ليتم تشغيلها بعد تحميل مكتبة analytics.js وجاهزة للتشغيل.
  • تضيف هذه الأوامر أمرًا إلى قائمة انتظار الأوامر ga() بهدف إنشاء كائن أداة تتبّع جديد للموقع المحدّد من خلال المعلّمة'UA-XXXXX-Y'.
  • إضافة أمر آخر إلى قائمة انتظار الأوامر ga() من أجل إرسال مشاهدة صفحة إلى "إحصاءات Google" للصفحة الحالية

على الرغم من أن البيانات التي يتم جمعها من مرات مشاهدة الصفحة وحدها مفيدة، فإنها لا تروي الخبر بأكمله. للحصول على صورة أفضل عن تجربة المستخدمين في موقعك الإلكتروني أو تطبيقك، يجب إرسال بيانات التفاعل الإضافية إلى "إحصاءات Google".

يدعم "إحصاءات Google" العديد من أنواع بيانات التفاعل: مشاهدات الصفحة والأحداث والتفاعلات الاجتماعية والاستثناءات وتوقيتات المستخدمين وليس آخرًا. لإرسال بيانات توقيت المستخدم إلى "إحصاءات Google"، يمكنك استخدام توقيع الأمر التالي:

ga('send', 'timing', timingCategory, timingVar, timingValue);

حيث timingCategory هي سلسلة تسمح لك بتنظيم نتائج التوقيت في مجموعة منطقية، timingVar هي المتغيّر الذي تقيسه، وtimingValue هي المدة الزمنية بالمللي ثانية.

للتعرّف على كيفية إجراء ذلك، يمكن تعديل عبارة console.log في الدالة measureCssUnblockTime على النحو التالي:

ga('send', 'timing', 'CSS', 'unblock', measureDuration('css:unblock'));

على الرغم من أن الرمز المذكور أعلاه سيعمل في بعض الحالات، إلا أن هناك أمران مهمان يجب أن تكون على دراية بهما:

  • أدت الخطوة السابقة إلى تعديل دالة measureDuration ليتم تشغيلها فقط إذا كان المتصفِّح يتيح واجهة برمجة تطبيقات User Timing، ما يعني أحيانًا أنّها ستعرض undefined. نظرًا لعدم وجود سبب لإرسال البيانات غير المحدّدة إلى"إحصاءات Google" (وفي بعض الحالات قد يؤدي ذلك إلى إفساد تقاريرك)، يجب عدم إرسال نتيجة التوقيت هذه إلا إذا كان measureDuration يعرض قيمة.
  • عندما يتم عرض قيمة من قِبل measureDuration، يتم ضبط DOMHighResTimeStamp على درجة دقة تزيد عن المللي ثانية. بما أنّ timingValue في "إحصاءات Google" يجب أن يكون عددًا صحيحًا، يجب تقريب القيمة التي تعرضها measureDuration.

لمراعاة هذه النقاط، عدِّل بيان الإرجاع في دالة measurementDuration لتقريب قيمة الإرجاع:

function measureDuration(mark, opt_reference) {
  if (window.__perf) {
    // ...
    return Math.round(measure.duration);
  }
}

وعدِّل أوامر التوقيت ليتم تشغيلها فقط إذا كانت هناك قيمة للمقياس المعنيّ. على سبيل المثال، يجب تعديل دالة measureCssUnblockTime على النحو التالي:

function measureCssUnblockTime() {
  var cssUnblockTime = measureDuration('css:unblock');
  if (cssUnblockTime) {
    ga('send', 'timing', 'CSS', 'unblock', cssUnblockTime);
  }
}

ولن تحتاج إلى إجراء تحديثات مماثلة لجميع وظائف القياس الأخرى. بعد الانتهاء من ذلك، من المفترض أن يظهر ملف Perf-analytics.js النهائي بالشكل التالي:

window.onload = function() {
  measureCssUnblockTime();
  measureWebfontPerfAndFailures();
  measureImagesVisibleTime();
  measureJavaSciptExecutionTime();
};


/**
 * Calculates the time duration between the responseEnd timing event and when
 * the CSS stops blocking rendering, then sends this measurement to Google
 * Analytics via a timing hit.
 */
function measureCssUnblockTime() {
  var cssUnblockTime = measureDuration('css:unblock');
  if (cssUnblockTime) {
    ga('send', 'timing', 'CSS', 'unblock', cssUnblockTime);
  }
}


/**
 * Calculates the time duration between the responseEnd timing event and when
 * the web fonts are downloaded and active, then sends this measurement to
 * Google Analytics via a timing hit. If an error occurs loading the font, an
 * error event is sent to Google Analytics.
 */
function measureWebfontPerfAndFailures() {
  if (window.Promise) {
    new Promise(function(resolve, reject) {
      var loaded = /wf-(in)?active/.exec(document.documentElement.className);
      var success = loaded && !loaded[1]; // No "in" in the capture group.
      if (loaded) {
        success ? resolve() : reject();
      }
      else {
        var originalAciveCallback = WebFontConfig.active;
        WebFontConfig.inactive = reject;
        WebFontConfig.active = function() {
          originalAciveCallback();
          resolve();
        };
        // In case the webfont.js script failed to load.
        setTimeout(reject, WebFontConfig.timeout);
      }
    })
    .then(function() {
      var fontsActiveTime = measureDuration('fonts:active');
      if (fontsActiveTime) {
        ga('send', 'timing', 'Fonts', 'active', fontsActiveTime);
      }
    })
    .catch(function() {
      ga('send', 'event', 'Fonts', 'error');
    });
  }
}


/**
 * Calculates the time duration between the responseEnd timing event and when
 * all images are loaded and visible on the page, then sends this measurement
 * to Google Analytics via a timing hit.
 */
function measureImagesVisibleTime() {
  var imgVisibleTime = measureDuration('img:visible');
  if (imgVisibleTime) {
    ga('send', 'timing', 'Images', 'visible', imgVisibleTime);
  }
}


/**
 * Calculates the time duration between the responseEnd timing event and when
 * all synchronous JavaScript files are downloaded and executed, then sends
 * this measurement to Google Analytics via a timing hit.
 */
function measureJavaSciptExecutionTime() {
  var jsExecuteTime = measureDuration('js:execute');
  if (jsExecuteTime) {
    ga('send', 'timing', 'JavaScript', 'execute', jsExecuteTime);
  }
}


/**
 * Accepts a mark name and an optional reference point in the navigation timing
 * API and returns the time duration between the reference point and the last
 * mark (chronologically). The return value is rounded to the nearest whole
 * number to be compatible with Google Analytics.
 * @param {string} mark The mark name.
 * @param {string=} opt_reference An optional reference point from the
 *     navigation timing API. Defaults to 'responseEnd'.
 * @return {?number} The time duration as an integer or undefined if no
 *     matching marks can be found.
 */
function measureDuration(mark, opt_reference) {
  if (window.__perf) {
    var reference = opt_reference || 'responseEnd';
    var name = reference + ':' + mark;

    // Clears any existing measurements with the same name.
    performance.clearMeasures(name);

    // Creates a new measurement from the reference point to the specified mark.
    // If more than one mark with this name exists, the most recent one is used.
    performance.measure(name, reference, mark);

    // Gets the value of the measurement just created.
    var measure = performance.getEntriesByName(name)[0];

    // Returns the measure duration.
    return Math.round(measure.duration);
  }
}

ويجب أن يظهر ملف index.html النهائي على النحو التالي:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Performance Analytics Demo</title>

  <!-- Start navigation timing feature detect -->
  <script>window.__perf = window.performance && performance.mark;</script>
  <!-- End navigation timing feature detect -->

  <!-- Start fonts -->
  <script>
  window.WebFontConfig = {
    google: {families: ['Roboto:400,700,400italic']},
    timeout: 10000,
    active: function() {
      __perf && performance.mark('fonts:active');
    }
  };
  </script>
  <script async src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
  <!-- End fonts -->

  <!-- Start CSS -->
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  <style>
    body { font-family: Roboto, sans-serif; margin: 1em; }
    img { float: left; height: auto; width: 33.33%; }
    .gallery { overflow: hidden; }
  </style>
  <script>__perf && performance.mark('css:unblock');</script>
  <!-- End CSS -->

</head>
<body>

  <div class="container">

    <!-- Start images -->
    <div class="gallery">
      <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/1/">
      <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/2/">
      <img onload="__perf && performance.mark('img:visible')" src="http://lorempixel.com/380/200/animals/3/">
    </div>
    <script>__perf && performance.mark('img:visible')</script>
    <!-- End images -->

    <h1>Performance Analytics Demo</h1>
    <p>Real performance data from real users.</p>

  </div>

  <!-- Start JavaScript -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  <script>__perf && performance.mark('js:execute');</script>
  <!-- End JavaScript -->

  <!-- Start analytics tracking snippet -->
  <script>
  window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('send', 'pageview');
  </script>
  <script async src="https://www.google-analytics.com/analytics.js"></script>
  <!-- End analytics tracking snippet -->

  <!-- Start performance analytics -->
  <script async src="perf-analytics.js"></script>
  <!-- End performance analytics -->

</body>
</html>

عند تحميل هذه الصفحة وإلقاء نظرة على الطلبات في لوحة الشبكة، سيظهر لك شيء مثل ما يلي:

لقطة شاشة يوم 10-05-2016 في الساعة 6.57.23 مساءً.png

يفيد ذلك، ولكن قد يكون من الصعب فحص هذه البيانات باعتبارها طلبًا مشفّرًا بعنوان URL. وفي حال عدم ظهور هذه الطلبات لأي سبب من الأسباب، سيكون من الصعب جدًا تتبُّع أماكن تعذُّرها.

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

تحديث عنوان URL لمقتطف analytics.js في index.html إلى analytics_debug.js وفتح وحدة تحكم المتصفّح، وستظهر لك البيانات المطبوعة التي تبدو بالشكل التالي:

لقطة شاشة يوم 10-05-2016 في الساعة 6.54.13 مساءً.png

الآن بعد أن تعرَّفت على كيفية تنفيذ قياس الأداء لهذه الصفحة التجريبية، يمكنك تجربتها في موقعك الإلكتروني وإرسال بيانات المستخدمين الفعلية إلى "إحصاءات Google".

إعداد تقارير عن البيانات التي تجمعها

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

للوصول إلى تقارير توقيت المستخدم في "إحصاءات Google"، انقر على علامة التبويب "إعداد التقارير" في الجزء العلوي، حدد &quot؛السلوك &gt؛ سرعة الموقع &gt؛ توقيتات المستخدم&;؛ من شريط التنقل الجانبي (أو اتبع التعليمات لعرض تقرير توقيتات المستخدم من مركز المساعدة).

عند تحميل تقرير "أوقات المستخدم" في "إحصاءات Google"، من المفترض أن تتمكن من رؤية فئات التوقيت التي تتوافق مع البيانات التي أرسلتها. انقر على أيٍّ منها لعرض تمثيلات بصرية لبيانات التوقيت. الصورة التالية هي مثال على أوقات تحميل الخطوط على موقع إلكتروني حقيقي باستخدام Google Fonts خلال آخر 24 ساعة.

لقطة شاشة يوم 10-05-2016 في الساعة 7.16.07 مساءً.png

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

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

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

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

عندما يتعلق الأمر بأي نوع من التحليلات، سترغب عادةً في البدء بنوع من الأسئلة، ثم معرفة كيفية استخدام البيانات للإجابة عن ذلك السؤال.

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

  • هل قيم المقاييس التي ينخفض تتبّعها أو تزيد بمرور الوقت؟
  • كيف يؤثر استخدام التخزين المؤقت بلا اتصال بالإنترنت من خلال مشغّل الخدمات أو التخزين المحلي على الأداء العام لموقعك الإلكتروني؟
  • هل يتم تحميل مواردك على النحو الأمثل؟ مثلاً، هل هناك فجوة واسعة بين وقت تنزيل المورد ووقت توفّره؟
  • هل هناك أي علاقة بين الأداء والمقاييس الأخرى التي يتم تتبُّعها (مثل معدّل الاشتراك والوقت المستغرَق في الموقع وعمليات الشراء وما إلى ذلك)؟

أخيرًا، إذا كنت تريد معرفة المزيد من المعلومات عن أداء الويب أو Google Analytics، إليك بعض الموارد الرائعة للبدء:

  • أدوات ومعلومات لمساعدتك في إنشاء مواقع إلكترونية عالية الأداء
    https://developers.google.com/speed/
  • أدوات وواجهات برمجة تطبيقات لمطوّري البرامج للاستفادة من نظام "إحصاءات Google" الأساسي
    https://developers.google.com/analytics/
  • دورات تدريبية على الإنترنت تشرح لك كيفية استخدام منتج "إحصاءات Google" نفسه (تعلّم من الأشخاص الذين يعملون في "إحصاءات Google" نفسه).
    https://analyticsacademy.withgoogle.com/