رویدادهای ورودی تراز شده

دیو تاپوسکا
Dave Tapuska

TL; DR

  • Chrome 60 با کاهش فرکانس رویداد، jank را کاهش می دهد و در نتیجه ثبات زمان بندی فریم را بهبود می بخشد.
  • متد getCoalescedEvents() که در کروم 58 معرفی شده است، همان اطلاعات رویدادی را که در طول این مدت داشته‌اید، ارائه می‌کند.

ارائه یک تجربه کاربری روان برای وب مهم است. زمان بین دریافت یک رویداد ورودی و زمانی که تصاویر واقعاً به روز می شوند مهم است و به طور کلی انجام کار کمتر مهم است. در چند نسخه اخیر Chrome، تأخیر ورودی را در این دستگاه‌ها کاهش داده‌ایم.

به منظور نرمی و عملکرد، در Chrome 60، ما در حال ایجاد تغییری هستیم که باعث می‌شود این رویدادها با فرکانس پایین‌تری رخ دهند و در عین حال جزئیات اطلاعات ارائه‌شده را افزایش دهیم. دقیقاً مانند زمانی که Jelly Bean منتشر شد و Choreographer را که ورودی‌های اندروید را تراز می‌کند به ارمغان آورد، ما در تمام پلتفرم‌ها ورودی همتراز با فریم را به وب می‌آوریم.

اما گاهی اوقات شما به رویدادهای بیشتری نیاز دارید. بنابراین، در Chrome 58 ، ما روشی به نام getCoalescedEvents() را پیاده‌سازی کردیم که به برنامه شما اجازه می‌دهد مسیر کامل اشاره‌گر را حتی زمانی که رویدادهای کمتری دریافت می‌کند، بازیابی کند.

بیایید ابتدا در مورد فرکانس رویداد صحبت کنیم.

کاهش فرکانس رویداد

بیایید برخی از اصول را درک کنیم: صفحه‌های لمسی ورودی را با فرکانس 60 تا 120 هرتز و موش‌ها ورودی را معمولاً با فرکانس 100 هرتز ارائه می‌کنند (اما می‌توانند در هر جایی تا 2000 هرتز باشند). با این حال نرخ تازه سازی معمولی یک مانیتور 60 هرتز است. پس واقعاً به چه معناست؟ این بدان معناست که ما ورودی را با نرخی بالاتر از آنچه در واقع نمایشگر را به روز می کنیم دریافت می کنیم. بنابراین بیایید به جدول زمانی عملکرد از ابزارهای devtool برای یک برنامه ساده نقاشی روی بوم نگاه کنیم.

در تصویر زیر، با غیر فعال بودن ورودی -aligned requestAnimationFrame() ، می توانید چندین بلوک پردازش در هر فریم را با زمان فریم متناقض مشاهده کنید. بلوک های کوچک زرد نشان دهنده آزمایش ضربه برای مواردی مانند هدف رویداد DOM، ارسال رویداد، اجرای جاوا اسکریپت، به روز رسانی گره شناور شده و احتمالاً محاسبه مجدد طرح و سبک ها هستند.

جدول زمانی عملکردی که زمان بندی فریم متناقض را نشان می دهد

پس چرا کارهای اضافی انجام می دهیم که باعث بروز رسانی بصری نمی شود؟ در حالت ایده آل، ما نمی خواهیم کاری انجام دهیم که در نهایت به نفع کاربر نباشد. با شروع در کروم 60، خط لوله ورودی ارسال رویدادهای پیوسته ( wheel ، mousewheel ، touchmove ، pointermove ، mousemove ) را به تأخیر می اندازد و آنها را درست قبل از بازگشت به فراخوان requestAnimationFrame() ارسال می کند. در تصویر زیر (با قابلیت فعال)، زمان فریم سازگارتر و رویدادهای پردازش زمان کمتری را مشاهده می کنید.

ما آزمایشی را با این ویژگی فعال در کانال‌های Canary و Dev انجام داده‌ایم و متوجه شده‌ایم که 35٪ تست‌های ضربه کمتری را انجام می‌دهیم که به رشته اصلی امکان می‌دهد بیشتر اوقات آماده اجرا شود.

نکته مهمی که توسعه‌دهندگان وب باید از آن آگاه باشند این است که هر رویداد مجزایی (مانند keydown ، keyup ، ماوس، mouseup ، mousedown touchstart ، touchend ) که رخ می‌دهد، فوراً همراه با رویدادهای معلق ارسال می‌شود و ترتیب نسبی حفظ می‌شود. با فعال کردن این ویژگی، بسیاری از کارها به جریان حلقه رویداد عادی تبدیل می‌شوند و یک بازه ورودی ثابت ارائه می‌دهند. این رویدادهای پیوسته را با رویدادهای scroll و resize که قبلاً در جریان حلقه رویداد در Chrome ساده شده‌اند، همراه می‌کند.

جدول زمانی عملکرد که زمان بندی فریم نسبتاً ثابتی را نشان می دهد.

ما دریافتیم که اکثریت قریب به اتفاق برنامه‌هایی که چنین رویدادهایی را مصرف می‌کنند، هیچ استفاده‌ای از فرکانس بالاتر ندارند. Android چندین سال است که رویدادها را همسو کرده است، بنابراین هیچ چیز جدیدی وجود ندارد، اما سایت‌ها ممکن است رویدادهای با جزئیات کمتری را در پلتفرم‌های دسکتاپ تجربه کنند. همیشه یک مشکل با رشته های اصلی janky وجود داشته است که باعث ایجاد سکسکه برای صافی ورودی می شود، به این معنی که ممکن است هر زمان که برنامه در حال انجام کار است، جهش هایی را در موقعیت خود مشاهده کنید و این امر باعث می شود که نتوانید بدانید که نشانگر چگونه از یک نقطه به نقطه دیگر رسیده است.

متد getCoalescedEvents()

همانطور که گفتم، سناریوهای نادری وجود دارد که برنامه ترجیح می دهد مسیر کامل اشاره گر را بداند. بنابراین برای رفع مواردی که در آن پرش‌های بزرگ و کاهش تعداد رویدادها مشاهده می‌کنید، در Chrome 58 ، افزونه‌ای را برای رویدادهای اشاره‌گر به نام getCoalescedEvents() راه‌اندازی کردیم. و در زیر مثالی از نحوه مخفی شدن jank در رشته اصلی از برنامه در صورت استفاده از این API آورده شده است.

مقایسه رویدادهای استاندارد و ادغام شده

به‌جای دریافت یک رویداد، می‌توانید به مجموعه رویدادهای تاریخی که باعث این رویداد شده‌اند دسترسی داشته باشید. Android ، iOS و Windows همگی APIهای بسیار مشابهی در SDKهای بومی خود دارند و ما در حال نمایش یک API مشابه در وب هستیم.

معمولاً یک برنامه طراحی ممکن است با نگاه کردن به انحرافات روی رویداد، یک نقطه را ترسیم کرده باشد:

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() هیچ تاثیری بر روی رویداد والد نخواهد داشت.