تحسين عملية إغلاق الصفحة في طلبات XMLHttpRequest المتزامنة

Joe Medley
Joe Medley

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

يجب تغيير هذه الممارسة، وقد بدأ المتصفّحات في الاستجابة لذلك. XMLHttpRequest() محدّدة مسبقًا لإيقافها نهائيًا وإزالتها. تتّخذ الإصدار 80 من Chrome الخطوة الأولى من خلال عدم السماح بإجراء طلبات متزامنة داخل العديد من معالجات الأحداث، وتحديدًا beforeunload وunload وpagehide وvisibilitychange عند تشغيلها أثناء عملية الرفض. أصدرت WebKit مؤخرًا أيضًا تعديلاً يتضمّن تغيير السلوك نفسه.

سأقدّم وصفًا موجزًا للخيارات المتاحة لمن يحتاجون إلى وقت لتعديل مواقعهم الإلكترونية، وسأوضّح البدائل المتاحة لـ XMLHttpRequest().

عمليات الإيقاف المؤقت

يريد Chrome أن يوفّر وقتًا للمطوّرين لإزالة الاعتماد على XMLHttpRequest()، لذلك قدّمنا خيارات إيقاف مؤقتة.

الانضمام إلى تجربة أصل باستخدام هذه الطريقة، يمكنك إضافة رمز مميّز خاص بالمصدر إلى عناوين صفحاتك، ما يتيح إجراء طلبات XMLHttpRequest() متزامنة. سينتهي هذا الخيار قبل وقت قصير من طرح الإصدار 89 من Chrome، أي في وقت ما خلال شهر مارس 2021. يمكن لعملاء Chrome Enterprise أيضًا استخدام علامة السياسة AllowSyncXHRInPageDismissal التي تنتهي في الوقت نفسه.

الحلول البديلة

بغض النظر عن الطريقة التي ترسل بها البيانات إلى الخادم، من الأفضل تجنُّب الانتظار إلى حين إلغاء تحميل الصفحة لإرسال جميع البيانات في وقت واحد. بالإضافة إلى أنّ عملية إلغاء التحميل تؤدي إلى تقديم تجربة سيئة للمستخدم، فهي غير موثوقة على المتصفحات الحديثة، وتتسبّب في فقدان البيانات إذا حدث خطأ ما. على وجه التحديد، لا يتم غالبًا تنشيط أحداث إلغاء التحميل على متصفّحات الأجهزة الجوّالة لأنّه توجد طرق عديدة لإغلاق علامة تبويب أو متصفّح على أنظمة التشغيل للأجهزة الجوّالة بدون تنشيط الحدث unload. في XMLHttpRequest()، كان استخدام حمولات صغيرة خيارًا متاحًا. أصبح ذلك شرطًا الآن. يبلغ الحدّ الأقصى لحجم الملف الذي يمكن تحميله في كل من البديلَين 64 كيلوبايت لكل سياق، وذلك وفقًا للمواصفات.

التحقّق من الاتصال

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

window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

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

SendBeacon()

SendBeacon() تستخدم في الواقع Fetch API في الخلفية، وهذا هو السبب في أنّها تخضع للقيود نفسها المتعلقة بحجم الحمولة البالغ 64 كيلوبايت، كما أنّها تضمن استمرار الطلب بعد إلغاء تحميل الصفحة. وتتمثّل ميزته الأساسية في بساطته. يتيح لك إرسال بياناتك باستخدام سطر واحد من الرمز:

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

الخاتمة

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