浏览器页面加载过程
浏览器在加载的时候会用到GUI渲染线程和JavaScript引擎线程,其中GUI渲染线程负责渲染浏览器HTMl元素,Javascript引擎线程主要负责处理Javascript脚本程序
由于Javascript在执行过程中还可能会改动页面结构样式,因此它们直接被设计为互斥关系,当Javascript引擎执行时,GUI线程会被挂起
浏览器解析HTML内容是从上到下解析HTML的元素,所以在head中写script标签一定要慎重,因为上面说当Javascript引擎执行时GUI引擎会被挂起,如果解析js时间过长会造成页面卡顿,如果想在head写script标签可以加async
HTML 与 DOM 有什么不同
官方描述:文档对象模型(DOM)是 HTML 和 XML 文档的编程接口。 也就是说dom是用来操作和描述HTML文档的接口如果说浏览器用HTML来描述网页的结构并渲染,那么使用DOM则可以获取网页的结构并进行操作。一般来说,我们使用js操作dom接口就能实现页面的动态变化,以及用户的交互操作,比如我们可以通过js获取dom,并对其做一些操作
DOM 解析
在浏览器中HTML会被解析成Dom树, 我们常常会对页面功能进行抽象,并封装成组件。但不管怎么进行整理,页面最终依然是基于 DOM 的树状结构,因此组件也是呈树状结构,组件间的关系也同样可以使用parent/child/sibling这样的方式来描述。
虚拟DOM
虚拟DOM其实是用来模拟真实DOM的中间产物,大致可分3个过程
-
- 用js对象模拟DOM树,得到一颗虚拟DOM树
-
- 当页面数据变更时,生成新的虚拟DOM树,比较新旧两颗虚拟DOM树的差异
-
- 把差异应用到真正的DOM树上
事件委托
浏览器中各个元素中接收事件的顺序包括事件捕获阶段、目标阶段、事件冒泡阶段。基于冒泡机制,可以将子元素要做的事情委托给父元素来处理,这就是事件委托
举个例子,现在有这样一个结构一个ul下面有3个li那么给这几个li添加点击事件呢,并知道哪个被点击了呢
自然能想到下面的代码
let class_list = [".ele1", ".ele2", ".ele3"];
function handleClick(e) {
console.log(e.target);
}
for (let item of class_list) {
console.log();
document.querySelector(item).addEventListener("click", handleClick, false);
}
发现效果实现了也很满意
其实如果通过事件委托来写这段代码,大可不必这么麻烦,我们只需要监听ul就行,我们来看看事件委托版的代码
function handleClick(e) {
console.log(e.target);
}
document.querySelector('ul').addEventListener("click", handleClick, false);
经过测试以后发现效果是一样的,这次是把事件委托给了父节点来处理,问题来了这样仅仅是为了省代码嘛,其实不然,将事件委托给父节点,我们对子元素的增加、修改、删除、移动等都不需要事件绑定了,而且每次对事件监听都是不小的性能消耗,试想一下,如果有成千上万的节点呢。因此使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较简单和基础的一个做法
那么就会想到既然事件委托这么好用,是不是可以直接在body进行事件委托,其实啊并不推荐这么做,由于浏览器进行页面渲染的时候会有合成步骤,合成的过程会先将页面分成不同的合成层,而用户与浏览器交换的时候需要接受事件,此时浏览器会将页面上具有事件处理程序的区域进行标记,被标记的区域会与主线程进行通信,如果我们页面一些元素啊,不想进行与用户的交互,合成器线程也必须与主线程同行,并在每次事件发生的时候进行等待,这种情况我们可以使用passive:true选项来解决,写法参照
addEventListener(type, listener, {
capture: false,
passive: false,
once: false
})
这里我查了下大概在2015年底把,对addEventListener的第三个参数进行了调整,我不知道是不是很多人和我一样只知道第三个参数可以为true和false,链接我放在下面了 www.cnblogs.com/ziyunfei/p/…