سيحدّ إصدار Chrome 88 (كانون الثاني/يناير 2021) بشكل كبير من أدوات ضبط الوقت المرتبطة في JavaScript ل الصفحات المخفية في ظروف معيّنة. سيؤدي ذلك إلى تقليل استخدام وحدة المعالجة المركزية (CPU)، ما يؤدي بدوره إلى تقليل استخدام البطارية. هناك بعض الحالات الشاذة التي سيؤدي فيها ذلك إلى تغيير السلوك، ولكن غالبًا ما يتم استخدام الموقّتات في الحالات التي تكون فيها واجهة برمجة تطبيقات مختلفة أكثر فعالية وموثوقية.
حسنًا، كان هذا الشرح مليئًا بالمصطلحات الفنية وغير واضح بعض الشيء. لنطّلِع على التفاصيل…
المصطلحات
الصفحات المخفية
بشكل عام، تعني الحالة مخفية أنّ علامة تبويب مختلفة نشطة أو أنّ النافذة قد تم تصغيرها، ولكن قد تصنّف المتصفّحات الصفحة على أنّها مخفية عندما يكون محتواها غير مرئي تمامًا. توفّر بعض المتصفّحات ميزات إضافية، ولكن يمكنك استخدام واجهة برمجة التطبيقات page visibility API في كل الأوقات للتتبّع عندما يعتقد المتصفّح أنّ مستوى الرؤية قد تغيّر.
أدوات ضبط الوقت في JavaScript
نقصد بـ موقّتات JavaScript setTimeout
وsetInterval
، اللذان يتيحان لك
تحديد موعد لمكالمة في وقت لاحق. إنّ الموقّتات مفيدة، ولن يتم التوقف عن استخدامها، ولكن في بعض الأحيان يتم استخدامها للاستعلام عن الحالة عندما يكون الحدث أكثر فعالية ودقة.
الموقّتات المتسلسلة
إذا استدعيت setTimeout
في المهمة نفسها كاستدعاء setTimeout
، يكون الاستدعاء الثاني
"مرتبطًا". باستخدام setInterval
، يكون كل تكرار جزءًا من
السلسلة. قد يكون من الأسهل فهم ذلك باستخدام الرمز البرمجي:
let chainCount = 0;
setInterval(() => {
chainCount++;
console.log(`This is number ${chainCount} in the chain`);
}, 500);
الشرط الثانوي:
let chainCount = 0;
function setTimeoutChain() {
setTimeout(() => {
chainCount++;
console.log(`This is number ${chainCount} in the chain`);
setTimeoutChain();
}, 500);
}
آلية عمل الحدّ من السرعة
يتمّ الحدّ من السرعة على مراحل:
الحد الأدنى من التقييد
يحدث ذلك للموقّتات المُجدوَلة عندما يكون أيّ مما يلي صحيحًا:
- أن تكون الصفحة مرئية
- رصدت الصفحة أصواتًا خلال آخر 30 ثانية. ويمكن أن يكون ذلك من أيّ من واجهات برمجة التطبيقات لإنشاء الأصوات، ولكن لا يتم احتساب المقطع الصوتي الصامت.
لا يتمّ الحدّ من معدّل التقدّم للموقّت، ما لم تكن المهلة المطلوبة أقلّ من 4 مللي ثانية، ويكون عدد السلاسل 5 سلاسل أو أكثر، وفي هذه الحالة يتم ضبط المهلة على 4 مللي ثانية. وهذه الميزة ليست جديدة، فقد كانت المتصفّحات تطبّقها منذ عدة سنوات.
التقييد
يحدث ذلك للموقّتات التي يتم جدولتها عندما لا يتم تطبيق الحد الأدنى من الحدّ من السرعة، وأي مما يلي صحيح:
- عدد السلاسل أقل من 5.
- تم إخفاء الصفحة لمدة تقل عن 5 دقائق.
- يتم استخدام WebRTC. على وجه التحديد، هناك
RTCPeerConnection
معRTCDataChannel
"مفتوح" أوMediaStreamTrack
"نشط".
سيتحقّق المتصفّح من الموقّتات في هذه المجموعة مرّة واحدة كل ثانية. وبما أنّه يتم التحقّق منها مرة واحدة في الثانية فقط، سيتم تجميع الموقّتات التي لها مهلة مماثلة معًا، ما يؤدّي إلى تقليل الوقت الذي تحتاجه علامة التبويب لتشغيل الرمز. وهذا الإجراء ليس جديدًا أيضًا، فكانت المتصفّحات تُجريه إلى حدّ ما منذ سنوات.
تقييد التحميل المكثّف
حسنًا، إليك الميزة الجديدة في الإصدار 88 من Chrome. يحدث الحدّ من السرعة بشكل مكثّف للموقّتات التي يتم تحديد موعد لها عندما لا تنطبق أيّ من شروط الحدّ الأدنى من الحدّ من السرعة أو الحدّ من السرعة، وجميع الشروط التالية صحيحة:
- تم إخفاء الصفحة لأكثر من 5 دقائق.
- عدد السلاسل هو 5 أو أكثر.
- إذا كانت الصفحة صامتة لمدة 30 ثانية على الأقل
- لا يتم استخدام WebRTC.
في هذه الحالة، سيتحقّق المتصفّح من الموقّتات في هذه المجموعة مرّة واحدة كل دقيقة. وهذا يعني أنّه سيتم تجميع الموقّتات معًا في عمليات الفحص هذه التي تتم بالدقائق.
الحلول البديلة
عادةً ما يكون هناك بديل أفضل للموقّت، أو يمكن دمج الموقّتات مع عنصر آخر للحفاظ على عمر وحدة المعالجة المركزية والبطارية.
استطلاعات الرأي على مستوى الولاية
هذا هو الاستخدام الأكثر شيوعًا (أو إساءة استخدام) للموقّتات، حيث يتم استخدامها باستمرار للقيام بعمليات استطلاع أو فحص لمعرفة ما إذا كان هناك أي تغيير. في معظم الحالات، يتوفّر بديل لميزة الدفع، حيث يُعلمك التطبيق بالتغيير عند حدوثه، لكي لا تضطر إلى التحقّق باستمرار. ابحث لمعرفة ما إذا كان هناك حدث يحقّق النتيجة نفسها.
إليك بعض الأمثلة:
- إذا كنت بحاجة إلى معرفة وقت دخول عنصر إلى إطار العرض، استخدِم
IntersectionObserver
. - إذا كنت بحاجة إلى معرفة وقت تغيير حجم عنصر، استخدِم
ResizeObserver
. - إذا كنت بحاجة إلى معرفة وقت تغيُّر نموذج DOM، استخدِم
MutationObserver
، أو الاستدعاءات المخصّصة لدورة حياة العنصر. - بدلاً من الاستعلام عن خادم، ننصحك باستخدام مقابس الويب أو الأحداث المُرسَلة من الخادم أو الرسائل الفورية أو عمليات جلب أحداث البث.
- إذا كنت بحاجة إلى التفاعل مع التغييرات في الصوت أو الفيديو، استخدِم أحداثًا مثل
timeupdate
وended
، أوrequestVideoFrameCallback
إذا كنت بحاجة إلى تنفيذ إجراء معيّن في كل إطار.
هناك أيضًا عوامل تشغيل الإشعارات إذا أردت عرض إشعار في وقت معيّن.
Animation
إنّ الصور المتحركة هي عناصر مرئية، لذا من المفترض ألا تستخدِم وقت وحدة المعالجة المركزية عندما تكون الصفحة مخفية.
إنّ requestAnimationFrame
يُعدّ أفضل بكثير في جدولة عمل الصور المتحركة من مؤقتات JavaScript. وتتم synchronization مع معدّل تحديث الشاشة على الجهاز، ما يضمن حصولك على callback واحد فقط لكل إطار قابل للعرض، كما يمنحك الحد الأقصى من الوقت لإنشاء هذا الإطار. بالإضافة إلى ذلك، سينتظر requestAnimationFrame
إلى أن تصبح الصفحة
مرئية، لكي لا يستخدم أي وحدة معالجة مركزية عندما تكون الصفحة مخفية.
إذا كان بإمكانك تحديد الرسوم المتحركة بالكامل مسبقًا، ننصحك باستخدام الرسوم المتحركة في CSS أو
Web Animations API. تتمتع هذه العناصر
بالمزايا نفسها التي تتمتع بها requestAnimationFrame
، ولكن يمكن للمتصفّح إجراء تحسينات إضافية مثل الدمج التلقائي، وهي عمومًا
أسهل في الاستخدام.
إذا كانت الصورة المتحركة ذات معدّل منخفض للإطارات (مثل مؤشر وميض)، تظلّ الموقّتات
الخيار الأفضل في الوقت الحالي، ولكن يمكنك دمجها مع requestAnimationFrame
للحصول على أفضل ما في العالمَين:
function animationInterval(ms, signal, callback) {
const start = document.timeline.currentTime;
function frame(time) {
if (signal.aborted) return;
callback(time);
scheduleFrame(time);
}
function scheduleFrame(time) {
const elapsed = time - start;
const roundedElapsed = Math.round(elapsed / ms) * ms;
const targetNext = start + roundedElapsed + ms;
const delay = targetNext - performance.now();
setTimeout(() => requestAnimationFrame(frame), delay);
}
scheduleFrame(start);
}
الاستخدام:
const controller = new AbortController();
// Create an animation callback every second:
animationInterval(1000, controller.signal, time => {
console.log('tick!', time);
});
// And stop it:
controller.abort();
الاختبار
سيتم تفعيل هذا التغيير لجميع مستخدمي Chrome في الإصدار 88 (كانون الثاني/يناير 2021). وهي مفعّلة حاليًا لنصف مستخدمي الإصدار التجريبي من Chrome وإصدار مطوّري البرامج وإصدار Canary. إذا أردت اختبارها، استخدِم علامة سطر الأوامر هذه عند تشغيل Chrome الإصدار التجريبي أو الإصدار المخصّص للمطوّرين أو الإصدار Canary:
--enable-features="IntensiveWakeUpThrottling:grace_period_seconds/10,OptOutZeroTimeoutTimersFromThrottling,AllowAggressiveThrottlingWithWebSocket"
تؤدي الوسيطة grace_period_seconds/10
إلى بدء عملية تقييد شديد بعد 10 ثوانٍ من إخفاء الصفحة، بدلاً من 5 دقائق كاملة، ما يسهّل الاطّلاع على تأثير عملية التقييد.
المستقبل
بما أنّ الموقّتات هي مصدر لاستخدام وحدة المعالجة المركزية بشكل مفرط، سنواصل البحث عن
طُرق يمكننا من خلالها الحدّ من استخدامها بدون إيقاف محتوى الويب، وواجهات برمجة التطبيقات التي يمكننا
إضافتها أو تغييرها لتلبية حالات الاستخدام. شخصيًا، أريد التخلص من الحاجة إلى
animationInterval
لصالح طلبات إعادة الاتصال الفعّالة ذات معدّل تكرار منخفض للصور المتحركة. إذا كانت لديك أي أسئلة، يُرجى التواصل معي على Twitter.
صورة الرأس تقدّمها هيثر كابريسكي على Unsplash.