浏览器如何处理页面操作
接收输入事件
- 浏览器进程接收键盘、鼠标事件、触摸手势等输入事件。浏览器进程仅知道手势发生位置,选项卡内部内容由渲染进程处理。
- 浏览器进程将事件类型、坐标发送给渲染进程
- 渲染进程通过查找事件目标并运行附加的事件侦听器来适当地处理事件
- 合成器线程接入输入事件
非快速可滚动区域
- 合成页面时,合成器线程标记页面的一个区域,该区域将事件处理程序附加为“非快速可滚动区域”。
- 通过获取此信息,合成器线程可以确保在该区域中发生事件时将输入事件发送到运行 JavaScript 的主线程。如果输入事件来自该区域之外,则合成器线程在不等待主线程的情况下继续合成新帧。
事件处理
下面程序中,整个页面都被标记为非快速可滚动区域,合成器线程也必须与主线程通信,并在每次输入事件进入时等待它,最终影响合成器平滑滚动能力。
document.body.addEventListener('touchstart', event = > {
if (event.target === area) {
event.preventDefault();
}
});
在事件监听器中传递 passive: true 选项,提示浏览器在主线程中监听事件,合成器线程也可以继续合成新帧。
document.body.addEventListener(
'touchstart',
event = > {
if (event.target === area) {
event.preventDefault();
}
}, {
passive: true
});
检查取消事件
通过 event.cancelable和event.preventDefault()检查取消事件。
也可通过CSS来完全消除事件处理程序。
document.body.addEventListener(
'pointermove',
event = > {
if (event.cancelable) {
event.preventDefault();
}
}, {
passive: true
});
#area {
touch - action: pan - x;
}
查找 event.target
当合成器线程向主线程发送输入事件时,首先要运行的是命中测试以查找事件目标。命中测试使用在渲染过程中生成的绘制记录数据来找出事件发生的点坐标下面的内容。
最小化事件派发到主线程
- 屏幕刷新率:60 次/秒
- 触摸屏触摸事件:60-120次/秒
- 鼠标:100次/秒
输入事件具有比屏幕刷新更高的保真度。主线程中触发过快的连续事件,会触发过多的命中测试和JS执行,导致页面抖动。为减少对主线程过度调用,Chrome合并连续事件(如 wheel,mousewheel,mousemove,pointermove, touchmove)并延迟调度,直到下一个requestAnimationFrame执行。
离散事件则立即执行,如keydown,keyup,mouseup,mousedown,touchstart,touchend
使用 getCoalescedEvents 得到帧内事件
大多数Web应用程序,合并事件应足以提供良好的用户体验。构建绘制应用程序并根据touchmove坐标放置路径等可能会丢失中间坐标以绘制平滑线,可以使用getCoalescedEvents指针事件中的方法来获取这些合并事件的信息。
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.
}
});