浏览器原理(四)

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战css

浏览器对事件的处理

浏览器经过对不一样事件的处理来知足各类交互需求,这一部分咱们一块儿看看从浏览器的视角,事件是什么,在此咱们先主要考虑鼠标事件。web

在浏览器的看来,用户的全部手势都是输入,鼠标滚动,悬置,点击等等都是。浏览器

当用户在屏幕上触发诸如 touch 等手势时,首先收到手势信息的是 Browser process, 不过 Browser process 只会感知到在哪里发生了手势,对 tab 内内容的处理是仍是由渲染进程控制的。markdown

事件发生时,浏览器进程会发送事件类型及相应的坐标给渲染进程,渲染进程随后找到事件对象并执行全部绑定在其上的相关事件处理函数。app

1628606667(1).jpg

前文中,咱们提到过合成器能够独立于主线程以外经过合成栅格化层平滑的处理滚动。若是页面中没有绑定相关事件,组合器线程能够独立于主线程建立组合帧。若是页面绑定了相关事件处理器,主线程就不得不出来工做了。这时候合成器线程会怎么处理呢?函数

这里涉及到一个专业名词「理解非快速滚动区域(non-fast scrollable region)」因为执行 JS 是主线程的工做,当页面合成时,合成器线程会标记页面中绑定有事件处理器的区域为 non-fast scrollable region ,若是存在这个标注,合成器线程会把发生在此处的事件发送给主线程,若是事件不是发生在这些区域,合成器线程则会直接合成新的帧而不用等到主线程的响应。post

image.png

web 开发中经常使用的事件处理模式是事件委托,基于事件冒泡,咱们经常在最顶层绑定事件:性能

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

上述作法很常见,可是若是从浏览器的角度看,整个页面都成了 non-fast scrollable region 了。测试

这意味着即便操做的是页面无绑定事件处理器的区域,每次输入时,合成器线程也须要和主线程通讯并等待反馈,流畅的合成器独立处理合成帧的模式就失效了。优化

image.png

因为事件绑定在最顶部,整个页面都成为了 non-fast scrollable region

为了防止这种状况,咱们能够为事件处理器传递 passive: true 作为参数,这样写就能让浏览器即监听相关事件,又让组合器线程在等等主线程响应前构建新的组合帧。

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

不过上述写法可能又会带来另一个问题,假设某个区域你只想要水平滚动,使用 passive: true 能够实现平滑滚动,可是垂直方向的滚动可能会先于event.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; 
}
复制代码

查找到事件对象

当组合器线程发送输入事件给主线程时,主线程首先会进行命中测试(hit test)来查找对应的事件目标,命中测试会基于渲染过程当中生成的绘制记录( paint records )查找事件发生坐标下存在的元素。

image.png

事件的优化

通常咱们屏幕的刷新速率为 60fps,可是某些事件的触发量会不止这个值,出于优化的目的,Chrome 会合并连续的事件(如 wheel, mousewheel, mousemove, pointermove, touchmove ),并延迟到下一帧渲染时候执行 。

而如 keydown, keyup, mouseup, mousedown, touchstart, 和 touchend 等非连续性事件则会当即被触发。

image.png

合并事件虽然能提示性能,可是若是你的应用是绘画等,则很难绘制一条平滑的曲线了,此时可使用 getCoalescedEvents API 来获取组合的事件。示例代码以下:

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.
    }
});
复制代码

image.png

花了很久来整理上面的内容,整理的过程收获还挺大的,也但愿这篇笔记能对你有所启发,若是有任何疑问,欢迎一块儿来讨论。

相关文章
相关标签/搜索