نظرة من الداخل على متصفح الويب الحديث (الجزء 4)

Mariko Kosaka

يأتي الإدخال إلى Compositor

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

إدخال الأحداث من منظور المتصفّح

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

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

حدث إدخال
الشكل 1: حدث الإدخال الذي يتم توجيهه من خلال عملية المتصفِّح إلى عملية العرض

يتلقّى المركّب أحداث الإدخال

الشكل 2: تمرير إطار العرض فوق طبقات الصفحة

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

التعرّف على المنطقة القابلة للتمرير بسرعة

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

منطقة محدودة وقابلة للتمرير السريع
الشكل 3: رسم تخطيطي للإدخال الموصوف للمنطقة القابلة للتمرير السريع

توخي الحذر عند كتابة معالِجات الأحداث

يُعد تفويض الأحداث نمطًا شائعًا لمعالجة الأحداث في تطوير الويب. بما أن فقاعات الأحداث، يمكنك يمكنك إرفاق معالج حدث واحد في العنصر العلوي وتفويض المهام بناءً على هدف الحدث. إِنْتَ قد تكون رأيت أو كتبت تعليمة برمجية مثل ما يلي.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

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

منطقة قابلة للتمرير السريع بالصفحة الكاملة
الشكل 4: رسم بياني للإدخال الموصوف للمنطقة التي يمكن تمريرها بسرعة والتي تغطي الصفحة بأكملها

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

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

التحقّق مما إذا كان الحدث قابلاً للإلغاء

الانتقال إلى أسفل الصفحة
الشكل 5: صفحة ويب بها جزء من الصفحة ثابت على التمرير الأفقي

تخيل أنّ هناك مربّعًا في صفحة تريد قصر اتجاه التمرير على التمرير الأفقي فقط.

يعني استخدام الخيار passive: true في حدث المؤشر أنّ الانتقال في الصفحة يمكن أن يكون سلسًا ولكن قد بدأ التمرير العمودي في الوقت الذي تريد preventDefault فيه للحد من اتجاه التمرير. يمكنك التحقّق من ذلك باستخدام طريقة event.cancelable.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

بدلاً من ذلك، يمكنك استخدام قاعدة CSS مثل touch-action لإزالة معالِج الحدث تمامًا.

#area {
  touch-action: pan-x;
}

العثور على هدف الحدث

اختبار النتائج
الشكل 6: السلسلة الرئيسية التي تبحث في سجلات الرسم وتسأل عن الرسم المرسوم على نقطة س.ص

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

تصغير عمليات إرسال الأحداث إلى سلسلة المحادثات الرئيسية

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

إذا تم إرسال حدث مستمر مثل touchmove إلى سلسلة المحادثات الرئيسية 120 مرة في الثانية، يصبح إلى تشغيل عدد مفرط من اختبارات النتائج وتنفيذ JavaScript مقارنة بمدى بطء تحديث الشاشة.

الأحداث التي لم تتم فلترتها
الشكل 7: الأحداث التي تغمر المخطط الزمني للإطار وتتسبب في تعطل الصفحة

لتقليل المكالمات المفرطة إلى سلسلة المحادثات الرئيسية، يدمج Chrome الأحداث المستمرة (مثل wheel وmousewheel وmousemove وpointermove وtouchmove ) ويتأخر الإرسال حتى قبل requestAnimationFrame مباشرةً.

أحداث مترابطة
الشكل 8: نفس الجدول الزمني كما كان من قبل ولكن يتم دمج الحدث وتأخيره

أي أحداث منفصلة، مثل keydown وkeyup وmouseup وmousedown وtouchstart وtouchend على الفور.

استخدام "getCoalescedEvents" للحصول على أحداث داخل الإطار

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

getCoalescedEvents
الشكل 9: مسار إيماءة اللمس السلس على اليسار، مسار محدود مدمج على اليمين
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

الخطوات التالية

نتناول في هذه السلسلة الأعمال الداخلية لمتصفح الويب. إذا لم تفكر أبدًا في سبب تقترح "أدوات مطوري البرامج" إضافة {passive: true} إلى معالج الأحداث أو لماذا يمكنك كتابة async. في علامة النص البرمجي، آمل أن تسلّط هذه السلسلة الضوء على سبب احتياج المتصفح إلى تلك الروابط لتقديم تجربة ويب أسرع وأكثر سلاسة.

استخدام Lighthouse

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

التعرّف على طريقة قياس الأداء

قد تختلف تعديلات الأداء باختلاف المواقع الإلكترونية، لذلك من الضروري قياس الأداء موقعك الإلكتروني وتحديد أفضل ما يناسب موقعك. لدى فريق أدوات مطوري البرامج في Chrome بعض البرامج التعليمية حول كيفية قياس أداء موقعك الإلكتروني

إضافة سياسة الميزات إلى موقعك الإلكتروني

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

الخاتمة

شكرًا

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

شكرًا جزيلاً لكل من راجع المسودات الأولية لهذه السلسلة، بما في ذلك (على سبيل المثال لا الحصر) إلى): أليكس راسل، بول أيرش، ميجين كيرني، إريك بيدلمان، ماتياس بينينز، أدي عثماني، كينوكو ياسودا، ناسكو أوسكوف، وتشارلي ريس.

هل استمتعت بهذه السلسلة؟ إذا كانت لديك أي أسئلة أو اقتراحات بشأن المشاركة المستقبلية، يسعدنا معرفة رأيك في قسم التعليقات أدناه أو @kosamari على Twitter.