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

ديف تابوسكا
"ديف تابوسكا"

الملخّص

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

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

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

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

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

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

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

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

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

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

أجرينا تجربة مع تفعيل هذه الميزة على قناتَي إصدار Canary ومطوّري البرامج، وتبيّن لنا أنّنا نُجري اختبارات نتائج أقل بنسبة% 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() أي تأثير على الحدث الرئيسي.