واجهة برمجة تطبيقات مراحل نشاط الصفحة

دعم المتصفح

  • Chrome: 68.
  • الحافة: 79.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

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

الخلفية

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

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

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

في الواقع، تتّخذ المتصفّحات اليوم تدابير نشطة للحفاظ على الموارد. للصفحات الموجودة في علامات التبويب في الخلفية، والعديد من المتصفحات (وخاصة Chrome) التي إلى القيام بالكثير من هذا - لتقليل البصمة الكربونية الإجمالية لمواردها.

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

Page Lifecycle API لحل هذه المشكلة عن طريق:

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

يوفّر هذا الحل إمكانية التنبؤ التي يحتاج إليها مطوّرو الويب لإنشاء المرونة في التعامل مع تدخلات النظام، وتسمح للمتصفحات بمزيد من تحسين موارد النظام بشكل مكثف، ليفيد جميع مستخدمي الويب في النهاية.

ستتناول بقية هذه المشاركة ميزات "دورة حياة الصفحة" الجديدة واستكشاف كيفية ارتباطها بجميع حالات أنظمة الويب الحالية والفعاليات. كما سيقدم أيضًا توصيات وأفضل الممارسات للأنواع من مطوّري برامج العمل يجب أن يقوموا به (ويجب عدم فعله) في كل ولاية.

نظرة عامة على حالات وأحداث الصفحة

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

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

تمثيل مرئي لتدفق الحالة والحدث موصوف في هذا المستند.
حالة وتدفق الأحداث في Page Lifecycle API

الولايات

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

الحالة الوصف
نشِط

تكون الصفحة بالحالة نشطة إذا كانت مرئية وتتضمن التركيز على الإدخال.

الحالات السابقة المحتمَلة:
سلبي (من خلال فعالية focus)
مجمّد (عبر الحدث resume، ثم pageshow حدث)

الحالات التالية المحتمَلة:
سلبي (من خلال الفعالية blur)

غير نشِطة

تكون الصفحة في حالة سلبية إذا كانت مرئية وتعمل لا تركز على الإدخال.

الحالات السابقة المحتمَلة:
نشطة (من خلال فعالية blur)
مخفية (عبر visibilitychange الحدث)
مجمّدة (عبر الحدث resume، ثم pageshow حدث)

الحالات التالية المحتمَلة:
نشطة (من خلال فعالية focus)
مخفية (عبر visibilitychange الحدث)

مخفية

تكون الصفحة بالحالة مخفية إذا لم تكن مرئية (ولم يتم تمييزها تجميدها أو تجاهلها أو إنهاؤها).

الحالات السابقة المحتمَلة:
سلبي (عبر حدث visibilitychange)
. مجمّد (عبر الحدث resume، ثم pageshow حدث)

الحالات التالية المحتمَلة:
سلبي (عبر حدث visibilitychange)
. مجمّد (من خلال الحدث freeze)
تم تجاهلها (لم يتم تنشيط أي أحداث)
تم الإنهاء (لم يتم تنشيط أي أحداث)

مجمّدة

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

توقف المتصفحات الصفحات للحفاظ على استخدام وحدة المعالجة المركزية (CPU)/البطارية/البيانات؛ هم تفعل ذلك أيضًا كطريقة لتفعيل التنقّل للخلف/للأمام — من خلال تجنُّب الحاجة إلى صفحة كاملة إعادة التحميل.

الحالات السابقة المحتمَلة:
مخفية (من خلال فعالية freeze)

الحالات التالية المحتمَلة:
نشطة (عبر حدث resume، ثم pageshow الحدث)
سلبي (عبر الحدث resume، ثم pageshow حدث)
مخفية (من خلال الحدث resume)
تم تجاهلها (لم يتم تنشيط أي أحداث)

تم إنهاؤها

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

الحالات السابقة المحتمَلة:
مخفية (من خلال فعالية pagehide)

الحالات التالية المحتمَلة:
لا ينطبق

تم التجاهل

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

في علامة التبويب غير مستبعد (بما في ذلك عنوان علامة التبويب والرمز المفضّل) يظهر عادةً للمستخدم بالرغم من إزالة الصفحة.

الحالات السابقة المحتمَلة:
مخفية (لم يتم تنشيط أي أحداث)
مجمّدة (لم يتم تنشيط أي أحداث)

الحالات التالية المحتمَلة:
لا ينطبق

فعاليات

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

الاسم التفاصيل
focus

عنصر DOM تم التركيز عليه.

ملاحظة: لا ينطبق حدث focus على تشير بالضرورة إلى تغيير في الحالة. إنه يشير فقط إلى تغيير الحالة إذا لم تكن الصفحة تتضمن سابقًا تركيز إدخال.

الحالات السابقة المحتمَلة:
سلبي

الحالات الحالية المحتمَلة:
نشطة

blur

فقد عنصر DOM تركيزه

ملاحظة: لا ينطبق حدث blur على تشير بالضرورة إلى تغيير في الحالة. إنه يشير فقط إلى تغيير الحالة إذا لم تعُد الصفحة تركّز على الإدخال (أي أنّ الصفحة لم يتم فقط التبديل من عنصر إلى آخر).

الحالات السابقة المحتمَلة:
نشطة

الحالات الحالية المحتمَلة:
سلبي

visibilitychange

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

الحالات السابقة المحتمَلة:
سلبي
مخفية

الحالات الحالية المحتمَلة:
سلبي
مخفية

freeze *

تمّ تجميد الصفحة للتو. أي تقييم القابلة للتجميد في قوائم انتظار المهام على الصفحة.

الحالات السابقة المحتمَلة:
مخفية

الحالات الحالية المحتمَلة:
مجمّدة

resume *

استأنف المتصفح صفحة مجمّدة.

الحالات السابقة المحتمَلة:
مجمّدة

الحالات الحالية المحتمَلة:
نشطة (إذا كانت متبوعة بـ حدث pageshow)
. سلبي (إذا كانت متبوعة بـ pageshow الحدث)
مخفية

pageshow

يتم الانتقال إلى إدخال سجلّ جلسة.

يمكن أن يكون إما تحميل صفحة جديدة تمامًا أو صفحة مأخوذة من ميزة "التخزين المؤقت للصفحات" إذا كانت الصفحة تم أخذه من ميزة "التخزين المؤقت للصفحات" وهي السمة persisted هي true، وبخلاف ذلك، false

الحالات السابقة المحتمَلة:
مجمّدة resume أو تنشيط الحدث المعني)

الحالات الحالية المحتمَلة:
نشطة
سلبي
مخفي

pagehide

يتم اجتياز إدخال سجل جلسة من.

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

الحالات السابقة المحتمَلة:
مخفية

الحالات الحالية المحتمَلة:
مجمّدة (event.persisted صحيحة، freeze الحدث التالي)
تم الإنهاء (event.persisted خطأ، unload متابعًا للحدث)

beforeunload

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

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

الحالات السابقة المحتمَلة:
مخفية

الحالات الحالية المحتمَلة:
تم إنهاؤها

unload

يتم الآن إلغاء تحميل الصفحة.

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

الحالات السابقة المحتمَلة:
مخفية

الحالات الحالية المحتمَلة:
تم الإنهاء

يشير الرمز * إلى حدث جديد تم تحديده من خلال Page Lifecycle API.

الميزات الجديدة المُضافة في الإصدار 68 من Chrome

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

في Chrome 68، يمكن للمطوّرين الآن ملاحظة متى يتم تجميد علامة تبويب مخفية إلغاء التجميد من خلال الاستماع إلى freeze وresume من الأحداث في document.

document.addEventListener('freeze', (event) => {
  // The page is now frozen.
});

document.addEventListener('resume', (event) => {
  // The page has been unfrozen.
});

من Chrome 68، يشمل الكائن document الآن wasDiscarded على Chrome لأجهزة الكمبيوتر المكتبي (يتم تتبُّع دعم Android في هذه المشكلة). لتحديد ما إذا كان قد تم تجاهل صفحة أثناء إخفاء الصفحة يمكنك فحص قيمة هذه السمة في وقت تحميل الصفحة (ملاحظة: ويجب إعادة تحميل الصفحات التي تم تجاهلها لاستخدامها مرة أخرى).

if (document.wasDiscarded) {
  // Page was previously discarded by the browser while in a hidden tab.
}

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

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

كيفية مراقبة حالات مراحل نشاط الصفحة في الرمز

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

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

الحالة مجمّدة ومنتهية، في من ناحية أخرى، لا يمكن رصدها إلا من خلال أداة معالجة الأحداث المعنية (freeze وpagehide) حسب الولاية المتغير.

كيفية مراقبة تغييرات الحالة

بناءً على الدالة getState() المحددة سابقًا، يمكنك متابعة جميع الصفحات تتغير حالة دورة الحياة مع الرمز التالي.

// Stores the initial state using the `getState()` function (defined above).
let state = getState();

// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
  const prevState = state;
  if (nextState !== prevState) {
    console.log(`State change: ${prevState} >>> ${nextState}`);
    state = nextState;
  }
};

// Options used for all event listeners.
const opts = {capture: true};

// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
  window.addEventListener(type, () => logStateChange(getState()), opts);
});

// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
  // In the freeze event, the next state is always frozen.
  logStateChange('frozen');
}, opts);

window.addEventListener('pagehide', (event) => {
  // If the event's persisted property is `true` the page is about
  // to enter the back/forward cache, which is also in the frozen state.
  // If the event's persisted property is not `true` the page is
  // about to be unloaded.
  logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);

تقوم هذه التعليمة البرمجية بثلاثة أشياء:

  • تحدد الحالة الأولية باستخدام الدالة getState().
  • تحدد الدالة التي تقبل الحالة التالية، وإذا كان هناك تغيير، بتسجيل تغييرات الحالة في وحدة التحكم.
  • إضافة التقاط أدوات معالجة الأحداث لجميع الأحداث الضرورية في مراحلها، والتي بدورها logStateChange()، مرورًا في الولاية التالية.

هناك شيء واحد يجب ملاحظته بشأن التعليمة البرمجية وهو أنه تتم إضافة جميع أدوات معالجة الأحداث إلى window ويمررون جميعًا {capture: true} وهناك بضعة أسباب لذلك:

  • لا تتطابق جميع أحداث "مراحل نشاط الصفحة" مع الهدف نفسه. pagehide، يتم تنشيط pageshow في window. visibilitychange وfreeze يتم إطلاق resume في document، وfocus وblur على عناصر DOM المعنية.
  • معظم هذه الأحداث لا تظهر كفقاعات، مما يعني أنه من المستحيل إضافتها أدوات معالجة الأحداث التي لا يتم التقاطها لعنصر أصل مشترك ومراقبة جميع منها.
  • يتم تنفيذ مرحلة الالتقاط قبل مرحلتي الهدف أو الفقاعة التفسيرية، وبالتالي المستمعين هناك يساعد في ضمان تشغيلها قبل أن تتمكن التعليمات البرمجية الأخرى من إلغائها.

اقتراحات المطوّرين في كل ولاية

من المهم، كمطوّرين، فهم حالات مراحل نشاط الصفحة و معرفة كيفية ملاحظتها في التعليمات البرمجية لأن نوع العمل الذي ينبغي عليك (ويجب لا) يعتمد على الحالة التي تكون فيها صفحتك.

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

الحالة اقتراحات المطوّرين
Active

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

يجب عدم منح الأولوية لأي أعمال غير مرتبطة بواجهة المستخدم وقد تحظر سلسلة التعليمات الرئيسية. إلى فترات عدم النشاط أو إلى عامل على الويب.

Passive

في الحالة السلبية التي لا يتفاعل فيها المستخدم مع الصفحة: ولكن لا يزال بإمكانهم رؤيته. هذا يعني أن تحديثات واجهة المستخدم والرسوم المتحركة يجب أن تظل بسلاسة، ولكن توقيت حدوث هذه التحديثات أقل أهمية.

عندما تتغير الصفحة من نشطة إلى سلبية، هو الوقت المناسب للحفاظ على حالة التطبيق غير المحفوظة.

Hidden

عندما تتغير الصفحة من سلبية إلى مخفية، من المحتمل ألا يتفاعل المستخدم معها مرة أخرى إلى أن تتم إعادة تحميلها.

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

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

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

Frozen

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

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

وعلى وجه الخصوص، من المهم أن:

عليك أيضًا الاحتفاظ بأي حالة عرض ديناميكي (مثل موضع التمرير). في عرض قائمة لانهائي) إلى sessionStorage (أو IndexedDB عبر commit()) التي تريد استعادتها إذا تم تم تجاهلها وإعادة تحميلها لاحقًا.

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

Terminated

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

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

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

Discarded

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

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

مرة أخرى، بما أن موثوقية وترتيب أحداث مراحل الحياة ليست تطبيقها باستمرار في جميع المتصفحات، فهي أسهل طريقة لاتباع النصائح في الجدول وهي استخدام PageLifecycle.js.

واجهات برمجة التطبيقات القديمة التي يجب تجنُّبها لمراحل النشاط

يجب تجنب الأحداث التالية متى أمكن ذلك.

حدث "إلغاء التحميل"

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

لهذا السبب، من الأفضل دائمًا الاعتماد على visibilitychange لتحديد وقت الجلسة وتنتهي، ونأخذ في الاعتبار الحالة المخفية آخر وقت موثوق فيه لحفظ بيانات التطبيقات والمستخدمين.

بالإضافة إلى ذلك، إنّ مجرد توفُّر معالج أحداث unload مسجَّل (عبر إما onunload أو addEventListener()) يمكن أن تمنع المتصفحات من لوضع الصفحات في ميزة "التخزين المؤقت للصفحات" لإجراء عمليات شراء أسرع. عمليات التحميل للخلف وللأمام.

يُوصى في جميع المتصفحات الحديثة باستخدام حدث pagehide لرصد عمليات التحميل المحتملة للصفحات (تُعرف أيضًا باسم تم الإنهاء) بدلاً من حدث unload. إذا كنت إلى دعم الإصدار 10 والإصدارات الأقدم من Internet Explorer، فينبغي عليك عرض رصد حدث pagehide واستخدام unload فقط في حال لم يكن المتصفّح متوافقًا pagehide:

const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';

window.addEventListener(terminationEvent, (event) => {
  // Note: if the browser is able to cache the page, `event.persisted`
  // is `true`, and the state is frozen rather than terminated.
});

حدث beforeunload

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

هناك فرق واحد بين beforeunload وunload هو الاستخدامات المشروعة لـ beforeunload. على سبيل المثال، عندما تريد تحذير المستخدم بأن لديهم تغييرات لم يتم حفظها، فسيفقدون إذا تابعوا إلغاء تحميل الصفحة.

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

بمعنى آخر، لا تستخدم هذه الطريقة (لأنّها تضيف أداة استماع إلى beforeunload بلا شروط):

addEventListener('beforeunload', (event) => {
  // A function that returns `true` if the page has unsaved changes.
  if (pageHasUnsavedChanges()) {
    event.preventDefault();

    // Legacy support for older browsers.
    return (event.returnValue = true);
  }
});

يمكنك بدلاً من ذلك استخدام هذه الطريقة (لأنّها تضيف أداة استماع beforeunload فقط عندما تكون وإزالة تلك البيانات في حال عدم توفّرها):

const beforeUnloadListener = (event) => {
  event.preventDefault();
  
  // Legacy support for older browsers.
  return (event.returnValue = true);
};

// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
  addEventListener('beforeunload', beforeUnloadListener);
});

// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
  removeEventListener('beforeunload', beforeUnloadListener);
});

الأسئلة الشائعة

لماذا لا يتم تحميل المحتوى؟ أو الولاية؟

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

تعمل صفحتي بشكل مهم عندما تكون مخفية، كيف يمكنني منع تجميدها أو تجاهلها؟

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

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

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

  • يتم تشغيل الصوت
  • استخدام WebRTC
  • تعديل عنوان الجدول أو رمزه المفضّل
  • عرض التنبيهات
  • إرسال إشعارات فورية

بالنسبة إلى ميزات القائمة الحالية المستخدمة لتحديد ما إذا كان من الممكن أن تكون علامة التبويب آمنة تم تجميدها أو تجاهلها، راجع: إرشادات للتجميد جارٍ التجاهل في متصفح Chrome.

ما هي ميزة "التخزين المؤقت للصفحات"؟

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

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

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

إذا لم أتمكّن من تشغيل واجهات برمجة التطبيقات غير المتزامنة في الحالة المجمدة أو المكتملة، كيف يمكنني حفظ البيانات في IndexedDB؟

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

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

بالنسبة إلى الرموز البرمجية التي يجب أن تعمل في الوقت الحالي، لدى المطوّرين خيارَين:

  • استخدام مساحة تخزين الجلسة: مساحة تخزين الجلسة متزامن ويستمر عبر عمليات تجاهل الصفحات.
  • استخدام IndexedDB من مشغّل الخدمات: يمكن لمشغِّل الخدمات تخزين البيانات في IndexedDB بعد إنهاء الصفحة أو تجاهلها. في freeze أو أداة معالجة الأحداث pagehide، يمكنك إرسال البيانات إلى مشغّل الخدمات من خلال postMessage()، ويمكن لعامل الخدمة التعامل مع حفظ البيانات.

اختبار تطبيقك في حالتَي التجميد أو التجاهُل

لاختبار أداء تطبيقك في حالتَي الحالة "مجمّدة" و"تم تجاهلها"، يمكنك الانتقال إلى chrome://discards لتجميد أو تجاهل أي من علامات التبويب المفتوحة.

يتجاهل Chrome واجهة المستخدم
واجهة المستخدم التي يتجاهلها Chrome

يتيح لك ذلك التأكّد من أنّ صفحتك تتعامل مع freeze وresume بشكل صحيح. الأحداث بالإضافة إلى علامة document.wasDiscarded عند إعادة تحميل الصفحات بعد تجاهل.

ملخّص

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

كلما بدأ المزيد من المطورين في تنفيذ واجهات برمجة التطبيقات الجديدة لمراحل نشاط الصفحة، زادت الأمان السماح للمتصفحات بتجميد وتجاهل الصفحات التي لا يتم استخدامها. هذا النمط يعني أن المتصفحات ستستهلك موارد الشبكة ووحدة المعالجة المركزية (CPU) والبطارية والشبكة وهو مكسب للمستخدمين.