أحداث الإدخال التي تمت محاذاتها

Dave Tapuska
Dave Tapuska

TL;DR

  • يقلل الإصدار 60 من Chrome من الارتباك عن طريق خفض معدّل تكرار الأحداث، ما يؤدي إلى تحسين اتساق توقيت اللقطات.
  • توفّر طريقة getCoalescedEvents()، التي تم طرحها في الإصدار 58 من Chrome، الكمية نفسها من معلومات الأحداث التي كانت متاحة لك في السابق.

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

من أجل تحسين الأداء وتعزيز سلاسة الاستخدام، سنُجري في الإصدار 60 من Chrome تغييرًا يؤدي إلى حدوث هذه الأحداث بمعدّل أقل مع زيادة دقة المعلومات المقدَّمة. تمامًا كما حدث عند إصدار Jelly Bean وتقديم ميزة Choreographer للمحاذاة على Android، نقدّم ميزة المحاذاة على الإطارات للويب على جميع المنصات.

ولكن في بعض الأحيان، تحتاج إلى المزيد من الأحداث. لذلك، في Chrome 58، نفّذنا طريقة تُسمى getCoalescedEvents()، والتي تسمح لتطبيقك باسترداد المسار الكامل للمؤشر حتى أثناءتلقّيه أحداثًا أقل.

لنتحدث أولاً عن معدّل تكرار الأحداث.

خفض معدّل تكرار الأحداث

لنلقِ نظرة على بعض الأساسيات: تُرسل الشاشات التي تعمل باللمس الإدخال بمعدّل من 60 إلى 120 هرتز، بينما تُرسل الفئران الإدخال عادةً بمعدّل 100 هرتز (ولكن يمكن أن يصل إلى 2000 هرتز). ومع ذلك، فإنّ معدّل التحديث المعتاد لشاشة العرض هو 60 هرتز. ماذا يعني ذلك في الواقع؟ ويعني ذلك أنّنا نتلقّى الإدخال بمعدّل أعلى من معدّل تعديل الشاشة. لنلقِ نظرة على مخطط زمني للأداء من أدوات المطوّرين لتطبيق رسم بسيط على لوحة.

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

مخطط زمني للأداء يعرض توقيتًا غير متّسق للإطارات

فلماذا نبذل جهدًا إضافيًا لا يؤدي إلى أي تعديلات مرئية؟ من الأفضل عدم تنفيذ أي عمل لا يعود بالفائدة على المستخدم في نهاية المطاف. اعتبارًا من Chrome 60، ستؤخّر مسار الإدخال إرسال الأحداث المستمرة (wheel، mousewheel، touchmove، pointermove، mousemove) وسترسلها مباشرةً قبل أن يتم تنفيذ requestAnimationFrame() callback. في الصورة أدناه (مع تفعيل الميزة)، يظهر لك وقت عرض اللقطة أكثر اتساقًا ووقتًا أقل لمعالجة الأحداث.

لقد أجرينا تجربة مع تفعيل هذه الميزة في قناتَي Canary و Dev، وتبيّن لنا أنّنا نجري اختبارات أقل بنسبة% 35، ما يتيح للسلسلة الرئيسية أن تكون جاهزة للتنفيذ بشكل متكرر.

ملاحظة مهمة يجب أن يعرفها مطوّرو الويب هي أنّه سيتم إرسال أي حدث متقطع (مثل keydown، keyup، mouseup، mousedown، touchstart، touchend) يحدث على الفور مع أي أحداث في انتظار المراجعة، مع الحفاظ على الترتيب النسبي. عند تفعيل هذه الميزة، يتم معالجة الكثير من العمل بشكل سلس في مسار حلقة الأحداث المعتاد، ما يوفر فاصل إدخال ثابتًا. يؤدي ذلك إلى توفير أحداث مستمرة متوافقة مع أحداث scroll وresize التي تم تبسيطها في مسار حلقة الأحداث في Chrome.

مخطط زمني للأداء يعرض توقيتًا متسقًا نسبيًا للإطارات

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

طريقة getCoalescedEvents()

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

مقارنة الأحداث العادية والأحداث المجمّعة

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

قد يرسم تطبيق الرسم عادةً نقطة من خلال الاطّلاع على العناصر المُحوَّلة في الحدث:

window.addEventListener("pointermove", function(event) {
    drawPoint(event.pageX, event.pageY);
});

يمكن تغيير هذا الرمز البرمجي بسهولة لاستخدام صفيف الأحداث:

window.addEventListener("pointermove", function(event) {
    var events = 'getCoalescedEvents' in event ? event.getCoalescedEvents() : [event];
    for (let e of events) {
    drawPoint(e.pageX, e.pageY);
    }
});

يُرجى العلم أنّه لا يتمّ تعبئة كلّ سمة في الأحداث المجمّعة. بما أنّه لا يتم إرسال الأحداث المجمّعة، بل يتمّ إرسالها مع الأحداث الأخرى، فإنه لا يتم اختبار نتائجها. ستتضمّن بعض الحقول، مثل currentTarget وeventPhase، قيمها التلقائية. لن يكون لاستدعاء الطرق ذات الصلة بالإرسال، مثل stopPropagation() أو preventDefault()، أي تأثير في الحدث الرئيسي.