التدخل ضد document.write()

هل ظهر لك مؤخرًا تحذير مماثل لما يلي في Developer Console في Chrome وكنت تتساءل عن سببه؟

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

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

من الأسباب المعروفة لضعف الأداء هو استخدام document.write() داخل الصفحات، وعلى وجه التحديد تلك الاستخدامات التي تحقِّق حقن النصوص البرمجية. على الرغم من أنّ الإجراء التالي يبدو غير ضار، فإنه يمكن أن يتسبب في مشاكل حقيقية للمستخدمين.

document.write('<script src="https://example.com/ad-inject.js"></script>');

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

بالنسبة إلى المستخدمين الذين لديهم اتصالات بطيئة، مثل شبكة الجيل الثاني (2G)، يمكن أن تؤدي النصوص البرمجية الخارجية التي يتم إدخالها ديناميكيًا من خلال document.write() إلى تأخير عرض محتوى الصفحة الرئيسية لعدة ثوانٍ، أو إلى تعذُّر تحميل الصفحات أو استغراق وقت طويل جدًا مما يؤدي إلى استسلام المستخدم. استنادًا إلى بيانات القياس في Chrome، تبيّن لنا أنّ loading صفحات الويب التي تعرض نصوصًا برمجية تابعة لجهات خارجية تم إدراجها من خلال document.write() عادةً ما يكون أبطأ مرتين من صفحات الويب الأخرى على شبكة الجيل الثاني.

جمعنا بيانات من تجربة ميدانية استمرت 28 يومًا على% 1 من مستخدمي Chrome الثابتين، وحصرناها على المستخدمين الذين يستخدمون اتصالات الجيل الثاني. تبيّن لنا أنّ% 7.6 من جميع عمليات تحميل الصفحات على شبكة الجيل الثاني (2G) تتضمّن نصًا برمجيًا واحدًا على الأقل يحظر التحليل على مستوى الموقع الإلكتروني، والذي تم إدراجه من خلال document.write() في مستند المستوى الأعلى. نتيجةً لحظرتحميل هذه النصوص البرمجية، لاحظنا التحسينات التالية على عمليات التحميل هذه:

  • زيادة بنسبة%10 في عمليات تحميل الصفحة التي تصل إلى مرحلة أول ظهور للمحتوى (تأكيد مرئي للمستخدم بأنّ الصفحة يتم تحميلها بفعالية)، زيادة بنسبة%25 في عمليات تحميل الصفحة التي تصل إلى مرحلة التحليل الكامل، وانخفاض بنسبة%10 في عمليات إعادة التحميل يشير ذلك إلى انخفاض في مستوى استياء المستخدم.
  • انخفاض %21 في متوسّط الوقت (أكثر من ثانية واحدة أسرع) إلى مرحلة سرعة عرض أول محتوى مرئي
  • خفض %38 من متوسّط الوقت المستغرَق لتحليل صفحة، ما يمثّل تحسُّنًا بنحو ست ثوانٍ، ما يؤدّي إلى تقليل الوقت المُستغرَق لعرض ما يهمّ المستخدم بشكل كبير

استنادًا إلى هذه البيانات، يتدخّل Chrome، بدءًا من الإصدار 55، نيابةً عن جميع المستخدمين عند رصد هذا النمط المعروف بأنه ضار من خلال تغيير كيفية التعامل مع document.write() في Chrome (راجِع حالة Chrome). على وجه التحديد، لن ينفذ Chrome عناصر <script> التي تم إدخالها من خلال document.write() عند استيفاء جميع الشروط التالية:

  1. يتصل المستخدم بشبكة بطيئة، خاصةً عندما يكون متصلاً بشبكة الجيل الثاني. (في المستقبل، قد يتم توسيع نطاق التغيير ليشمل المستخدمين الآخرين الذين يستخدمون اتصالات بطيئة، مثل شبكة الجيل الثالث (3G) أو شبكة Wi-Fi البطيئة).
  2. العنصر document.write() في مستند من المستوى الأعلى لا ينطبق التدخل على النصوص البرمجية document.written ضمن إطارات iframe لأنّها لا تحظر عرض الصفحة الرئيسية.
  3. النص البرمجي في document.write() يحظر المُحلِّل اللغوي. وسيستمر تنفيذ النصوص البرمجية التي تحتوي على السمتَين "async" أو "defer" .
  4. النص البرمجي غير مستضاف على الموقع الإلكتروني نفسه. بعبارة أخرى، لن يتدخل Chrome في النصوص البرمجية التي تتضمّن نطاقًا في المستوى الأعلى مسبوقًا باسم مطابقًا (مثل نص برمجي مستضاف على js.example.org تم إدراجه على www.example.org).
  5. النص البرمجي ليس متوفرًا في ذاكرة التخزين المؤقت لبروتوكول HTTP في المتصفّح. لن تواجه النصوص البرمجية في ذاكرة التخزين المؤقت تأخُّرًا في الشبكة وسيستمر تنفيذها.
  6. طلب الصفحة ليس إعادة تحميل. لن يتدخل Chrome إذا بدأ العميل عملية إعادة تحميل، وسيتم تنفيذ الصفحة كالمعتاد.

تستخدم المقتطفات التابعة لجهات خارجية أحيانًا document.write() لتحميل النصوص البرمجية. لحسن الحظ، تقدّم معظم الجهات الخارجية بدائل للتحميل غير المتزامن، والتي تسمح بتحميل النصوص البرمجية التابعة لجهات خارجية بدون حظر عرض بقية المحتوى على الصفحة.

كيف أحل هذه المشكلة؟

الإجابة البسيطة هي عدم إدراج نصوص برمجية باستخدام document.write(). ونحتفظ بمجموعة من الخدمات المعروفة التي تتيح استخدام أداة التحميل غير المتزامنة وننصحك بمواصلة التحقّق منها.

إذا لم يكن مقدّم الخدمة مدرَجًا في القائمة وكان يدعم تحميل النصوص البرمجية غير المتزامنة، يُرجى إعلامنا بذلك وسنعدّل الصفحة لمساعدة جميع المستخدمين.

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

إذا قدّم لك مقدّم الخدمة مقتطفًا يتضمّن document.write()، قد تتمكّن من إضافة سمة async إلى عنصر النص البرمجي، أو من إضافة عناصر النصوص البرمجية باستخدام واجهات برمجة تطبيقات DOM مثل document.appendChild() أو parentNode.insertBefore().

كيفية معرفة ما إذا كان موقعك الإلكتروني متأثرًا

هناك عدد كبير من المعايير التي تحدّد ما إذا كان سيتم فرض القيود، فكيف يمكنك معرفة ما إذا كنت متأثرًا بها؟

رصد الحالات التي يستخدم فيها المستخدم شبكة الجيل الثاني

لفهم التأثير المحتمل لهذا التغيير، عليك أولاً معرفة عدد المستخدمين الذين سيستخدمون شبكة الجيل الثاني. يمكنك رصد نوع الشبكة والسرعة الحالية للمستخدم باستخدام واجهة برمجة التطبيقاتNetwork Information API المتاحة في Chrome، ثم إرسال تنبيه إلى أنظمة الإحصاءات أو Metrics Real User (RUM).

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

رصد التحذيرات في "أدوات مطوّري البرامج في Chrome"

منذ الإصدار 53 من Chrome، تُصدر "أدوات مطوّري البرامج" تحذيرات بشأن عبارات document.write() التي تتضمّن مشاكل. على وجه التحديد، إذا كان طلب document.write() يستوفي المعايير من 2 إلى 5 (يتجاهل Chrome معايير الاتصال عند إرسال هذا التحذير)، سيظهر التحذير على النحو التالي:

تحذير بشأن كتابة المستند

من الرائع رؤية التحذيرات في Chrome DevTools، ولكن كيف يمكنك رصدها على مستوىٍ واسع؟ يمكنك التحقّق من عناوين HTTP التي يتم إرسالها إلى خادمك عند حدوث التدخل.

التحقّق من عناوين HTTP في مورد النص البرمجي

عند حظر نص برمجي تم إدراجه من خلال document.write، سيرسل Chrome العنوان التالي إلى المورد المطلوب:

Intervention: <https://shorturl/relevant/spec>;

عندما يتم العثور على نص برمجي تم إدخاله من خلال document.write ويمكن حظره في ظروف مختلفة، قد يرسل Chrome ما يلي:

Intervention: <https://shorturl/relevant/spec>; level="warning"

سيتم إرسال عنوان التدخل كجزء من طلب GET للنص البرمجي (بشكل غير متزامن في حال حدوث تدخل فعلي).

ما الذي يحمله المستقبل في جعبته؟

الخطة الأولية هي تنفيذ هذا الإجراء عند رصد استيفاء المعايير. بدأنا بعرض تحذير فقط في "وحدة تحكّم المطوّر" في Chrome 53. (تم طرح الإصدار التجريبي في تموز/يوليو 2016. نتوقع أن تصبح الإصدارات الثابتة متاحة لجميع المستخدمين في أيلول (سبتمبر) 2016.)

سنتدخل لحظر النصوص البرمجية المُحقَّقة لمستخدمي شبكة الجيل الثاني بشكلٍ مؤقت اعتبارًا من Chrome 54، الذي من المتوقّع أن يكون إصدارًا ثابتًا لجميع المستخدمين في منتصف تشرين الأول (أكتوبر) 2016. يمكنك الاطّلاع على مدخل حالة Chrome للحصول على مزيد من المعلومات.

وبمرور الوقت، نسعى إلى التدخل عندما يكون الاتصال بطيئًا لأي مستخدم (أي شبكة الجيل الثالث أو شبكة Wi-Fi بطيئة). اتّبِع إدخال حالة Chrome هذا.

هل يهمّك معرفة المزيد من المعلومات؟

لمزيد من المعلومات، يمكنك الاطّلاع على هذه المراجع الإضافية: