目录
diff算法 与 虚拟dom

浏览器渲染页面过程
1. 浏览器将HTML解析成一个DOM树
DOM树的构建过程是一个深度遍历的过程,也就是说当前节点的所有子节点够构建好之后,才会去构建当前节点的下一个兄弟节点。
2. 将CSS解析成 CSSOM 对象模型(DOM 和CSSOM是独立的数据结构)
浏览器在为页面上的任何对象计算最后一组样式时,浏览器都会从先从适用于该节点的最通用规则开始(如果某个节点是body的子元素,那就应用所有body的样式),然后通过应用更具体的规则(即“向下级联”)以递归的方式适用子节点的样式优化显示。
3. 根据DOM树和CSSOM来构建 Render Tree
有了Render Tree,浏览器就知道网页上有哪些节点,各个节点的CSS定义以及他们的从属关系,下一步就是根据当前窗口的大小计算每个节点在屏幕中的位置,称为layout。
4. 遍历 Render Tree,使用上一步计算出的每个节点的绝对像素绘制每个节点。
浏览器重排和重绘
当 DOM 的变化引起了几何属性(宽和高),浏览器需要重新计算元素的集合属性,同样其他元素的集合属性和位置也会因此受到影响。浏览器会使渲染树中的部分失效,并重新构造渲染树。这个过程称为重排(reflow)。
完成重排后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘(repaint)。
并不是所有的 DOM 变化都会影响几何属性,比如背景颜色的改变就不会影响长宽,这种情况下就只会发生一次重绘(并不需要重排),因为元素的布局没有改变。重排和重绘的操作对性能的影响很大,这点会在 DOM 的操作的性能分析中详细讲到。
浏览器异步机制
js 是单线程的,但浏览器是多线程。所以 js 如果想要执行异步任务,就需要浏览器其他线程的辅助。
浏览器解析js代码时, 执行栈优先执行同步代码。
如果(代码中从上到下)遇到异步代码(微任务、宏任务),就先将异步代码挂在任务队列中,
当所有同步代码执行完毕后,再依次将任务队列中的异步任务放在执行栈进行解析,在执行异步任务的过程中,如果遇到同步代码....遇到异步代码....
如此循环往复,形成事件循环。
事件循环 (Event Loop)
js是单线程的脚本语言,在同一时间,只能做同一件事,为了协调事件、用户交互、脚本、UI渲染和网络处理等行为,防止主线程阻塞,Event Loop方案应运而生...
js引擎在编译代码时:
遇到同步代码直接放入执行栈,
遇到一个异步代码,并不会一直等待异步代码的返回结果,而是挂在任务队列中
当执行栈中的所有同步任务都执行完毕时, 主线程处于闲置状态,就会去查找任务队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后:遇到同步代码时...遇到异步代码时...
如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。
每一轮都是先执行微任务,再执行宏任务。(如果某一轮的微任务中包含宏任务,则把宏任务放入当前宏任务列表末尾)
异步任务分为 宏任务(macrotask) 与 微任务 (microtask)
微任务:Promise async/await process.nextTick
宏任务:setTimeout setInterval Dom事件 Ajax请求
执行顺序:微任务 -> Dom 渲染 -> 宏任务
如果我们用alert事件打断js, 会发现:alert('promise then') 时页面dom并没有开始渲染,关掉alert后,dom渲染完成,然后 alert('setTimeout')
浏览器缓存
浏览器缓存分为强制缓存和协商缓存,优先读取强制缓存。
强制缓存分为expires和cache-control,而expires是一个特定的时间,是比较旧的标准和cache-control通常是一个具体的时间长度,比较新,优先级也比较高。
而协商缓存包括etag和last-modified,last-modified的设置标准是资源的上次修改时间,而etag是为了应对资源修改时间可能很频繁的情况出现的,是基于资源的内容计算出来的值,因此优先级也较高。
协商缓存与强制缓存的区别在于强制缓存不需要访问服务器,返回结果是200,协商缓存需要访问服务器,命中协商缓存的话,返回结果是304
事件流 -- 捕获与冒泡
addEventListener 最后一个参数默认为false,表示事件发生在冒泡阶段
http 状态码
101 协议升级
200 请求成功
301 永久重定向
302 临时重定向
304 协商缓存
404 客户端请求的错误,服务器无法理解
500 服务器端在执行时发生错误,无法完成请求