跳到主要内容

浏览器

浏览器是如何解析代码的?​

  • 解析HTML

    • HTML的解析是逐行解析。
    • 构建DOM树
  • 解析css

    • CSS选择器的读取顺序是从右向左
    • 因此浏览器会按照从右向左的顺序去读取选择器
  • 解析js

    • 浏览器中有一个js解析器的工具,专门用来解析我们的js代码
    • 解析器会找到js当中的所有变量、函数、参数等等

浏览器是如何解析JS代码和执行的​

V8 引擎执行 JS 代码

  • 解析阶段:V8引擎将JS代码 转换 为AST抽象语法树
  • AST抽象语法树 转换为字节码
  • 字节码再转换为机器码

浏览器工作原理​

浏览器的工作原理可以分为以下几个步骤:

  1. 输入网址:当你在浏览器的地址栏输入网址时,浏览器会向服务器请求该网址的内容。
  2. 服务器响应请求:服务器会返回网站的内容,这些内容通常包含 HTML、CSS 和 JavaScript 代码。
  3. 浏览器解析 HTML:浏览器会读取 HTML 代码,并根据这些代码在屏幕上显示出网站的内容。
  4. 浏览器解析 CSS:浏览器会读取 CSS 代码,并根据这些代码设置网站的样式。
  5. 浏览器执行 JavaScript:浏览器会读取 JavaScript 代码,并执行这些代码。JavaScript 可以用来控制网站的行为,例如动态地改变网站的内容或添加交互功能。
  6. 浏览器渲染内容

浏览器的渲染机制 【页面渲染html的过程】​

浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制。

1、构建DOM树(parse):渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node

  • 解析HTML文档,将其中的标签、属性、文本转换为DOM树 【DOM树表示网页的结构】

2、构建渲染树(construct):解析对应的CSS样式文件信息

  • 浏览器会去解析css样式,计算每个元素的样式信息

3、布局渲染树 (reflow/layout)

  • 从根节点递归调用,计算每一个元素的大小、位置,来得出元素在屏幕上的准确显示位置

4、绘制渲染树(paint/repaint)

  • 遍历渲染树,浏览器将每个节点转换为屏幕上的实际像素

1、解析html构建dom树

2、解析css构建render树(将CSS代码解析成树形的数据结构,然后结合DOM合并成render树)

3、布局render树(Layout/reflow),负责各元素尺寸、位置的计算

4、绘制render树(paint),绘制页面像素信息

5、渲染树创建好了,浏览器就可以根据渲染树把页面绘制到屏幕上。

  • 渲染好的东西绘制页面上面去显示给用户

浏览器遇到什么会停下来​

阻塞发生的情况:

  • 遇到script标签加载js的时候会加载js并且执行完毕才开始渲染
  • 因为js会对DOM进行操作,所以js阻塞DOM树的构建
  • 遇到js浏览器会停下来DOM构建,所以最好把js放在body底部
  • 其中一个原因就是为了不阻塞浏览器DOM树的构建,这也是为什么放在body上面的JS常常取不到想要的DO M节点,因为这个时候DOM树的构建还没有完成就被阻塞了
  • 当浏览器遇到一个 script 标记时,DOM 构建将暂停,直至脚本完成执行
  • 遇到alert会阻塞
  • css也会阻塞
  • css是由单独的下载线程异步下载的。

总结:

js会阻塞DOM的构建,一般js放在body底部

css加载不会阻塞DOM树的解析 css加载会阻塞渲染树(render树)的构建 css加载会阻塞后面js语句的执行

尽可能的提高css加载速度

  • 使用CDN
  • 对css进行压缩
  • 减少http请求数

理解浏览器沙箱​

  • 沙箱:就是一个环境,黑盒,在一个虚拟的环境中模拟真实世界,不对外界进行干扰

沙箱,即sandbox,顾名思义,就是让你的程序跑在一个隔离的环境下,不对外界的其他程序造成影响,通过创建类似沙盒的独立作业环境,在其内部运行的程序并不能对硬盘产生永久性的影响

  • 举个简单的例子,其实我们的浏览器,Chrome 中的每一个标签页都是一个沙箱(sandbox)。渲染进程被沙箱(Sandbox)隔离,网页 web 代码内容必须通过 IPC 通道才能与浏览器内核进程通信,通信过程会进行安全的检查。沙箱设计的目的是为了让不可信的代码运行在一定的环境中,从而限制这些代码访问隔离区之外的资源
    • IPC是Inter-Process Communication的缩写 ,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。

JS实现沙箱两种方式

  • 市面上现在流行两种沙箱模式,一种是使用iframe,还有一种是直接在页面上使用new Function + eval进行执行

为什么在一个浏览器中使用多个进程

每个进程内都有什么​

在什么情况下浏览器会创建进程​

浏览器安全控制​

  • X-XSS-Protection

    • 防止反射型XSS
  • Strict-Transport-Security

    • 强制使用HTTPS通信
  • CSP: 使用 W3C 提出的 CSP (Content Security Policy,内容安全策略),定义域名白名单

    内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻 击,包括跨站脚本 (XSS) 和数据注入等攻击。 这些攻击可用于实现从数据窃取到网站破坏或作为恶意软 件分发版本等用途。

    CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少XSS 攻击

    • HTTP 响应头 Content-Security-Policy 允许站点管理者在指定的页面控制用户代理的资源。除了少数例外,这条政策将极大地指定服务源 以及脚本端点。这将帮助防止跨站脚本攻击(Cross-Site Script) (XSS).
    text
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

浏览器内核的理解​

主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。 渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。

浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。

JS引擎则:解析和执行javascript来实现网页的动态效果。 最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

谈谈你对重绘和回流的理解。​

  • 回流也叫 重排: 简单来说,就是当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。
  • 重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,元素的位置信息不需要更新. 浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。

这也是为什么操作DOM是昂贵的,因为会触发浏览器的渲染 【重绘和回流】,更加消耗性能

触发回流​

1、一个 DOM 元素的几何尺寸变化,常见的几何属性有 width、height、padding、margin、left、top、border 等等, 这个很好理解。

2、使 DOM 节点发生 增减或者 移动。

3、读写 offset族、scroll族和 client族属性的时候,浏览器为了获取这些值,需要进行回流操作。

4、调用 window.getComputedStyle 方法。

  • 包含的任何基本计算后元素的所有CSS属性的值

知道了重绘和回流,在开发中有什么意义呢?​

由此我们可以看出, 重绘不一定导致回流,回流一定会导致重绘, 但这两个说到底都是吃性能的 ,我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。

当一个DOM元素的几何属性发生变化时,所有和它相关的节点(比如父子节点、兄弟节点等)的几何属性都需要进行重新计算,它会带来巨大的计算量。

当你要用到像这样的属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,你就要注意了!

  • (获取元素布局宽度/高度,获取元素相对视口的位置,获取屏幕宽度/高度)
  • 因为获取这些值,浏览器是要通过即时计算的,因此会触发回流
  • 除此之外,当我们调用了 getComputedStyle 方法,或者 IE 里的 currentStyle 时,也会触发回流。原理是一样的
  • 避免频繁使用 style,而是采用修改 class的方式。

    • 因为每次使用style修改样式,都会去触发一次渲染树的更改,从而导致相应的回流与重绘过程
    • 而我们把所有样式操作合并在一个class中,等于我们将所有的更改一次性发出,只触发一次渲染树
  • 使用 createDocumentFragment进行批量的 DOM 操作。

  • 对于 resize、scroll 等进行防抖/节流处理。

  • 添加 will-change: tranform ,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于 tranform, 任何可以实现合成效果的 CSS 属性都能用 will-change来声明。这里有一个实际的例子,一行 will-change: tranform拯救一个项目,点击直达

  • 使用translate替代position

    • 改变 position 是会导致浏览器进行重排,浏览器会重新计算受到影响的元素的几何位置,这种计算量是非常巨大的且慢的
    • translate不会触发回流

浏览器的Flush队列​

因为现代浏览器是很聪明的。浏览器自己也清楚,如果每次 DOM 操作都即时地反馈一次回流或重绘,那么性能上来说是扛不住的。于是它自己缓存了一个 flush 队列,把我们触发的回流与重绘任务都塞进去,待到队列里的任务多起来、或者达到了一定的时间间隔,或者“不得已”的时候,再将这些任务一口气出队

  • 何为 “不得已”的时候 ? 上面我们提到一些属性,即当你要用到像这样的属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,你就要注意了!,它们有很强的 即时性,当我们访问这些属性时,浏览器会为了获得此时此刻的、最准确的属性值,而提前将 flush 队列的任务出队——这就是所谓的“不得已”时刻

浏览器垃圾回收​

浏览器怎么进行垃圾回收

标记清除算法,GC会检测当前对象有没有被变量所引用,如果没有就回收

从三个点来回答什么是垃圾、如何捡垃圾、什么时候捡垃圾。

  1. 什么是垃圾
    • 不再需要,即为垃圾
    • 全局变量随时可能用到,所以一定不是垃圾
  2. 如何捡垃圾(遍历算法)
    • 标记空间中「可达」值。
      • 从根节点(Root)出发,遍历所有的对象。
      • 可以遍历到的对象,是可达的(reachable)。
      • 没有被遍历到的对象,不可达的(unreachable)
    • 回收「不可达」的值所占据的内存。
    • 做内存整理。
  3. 什么时候捡垃圾
    • 前端有其特殊性,垃圾回收的时候会造成页面卡顿。
    • 分代收集、增量收集、闲时收集。

浏览器中不同类型变量的内存都是何时释放?​

Javascritp 中类型:值类型,引用类型。

  • 引用类型
    • 在没有引用之后,通过 V8 自动回收。
  • 值类型
    • 如果处于闭包的情况下,要等闭包没有引用才会被 V8 回收。
    • 非闭包的情况下,等待 V8 的新生代切换的时候回收。

哪些情况会导致内存泄露?如何避免?​

内存泄露是指你「用不到」(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

以 Vue 为例,通常有这些情况:

  • 监听在 window/body 等事件没有解绑
  • 绑在 EventBus 的事件没有解绑
  • Vuex 的 $store,watch 了之后没有 unwatch
  • 使用第三方库创建,没有调用正确的销毁函数

解决办法:beforeDestroy 中及时销毁

  • 绑定了 DOM/BOM 对象中的事件 addEventListener ,removeEventListener。
  • 观察者模式 $on,$off处理。
  • 如果组件中使用了定时器,应销毁处理。
  • 如果在 mounted/created 钩子中使用了第三方库初始化,对应的销毁。
  • 使用弱引用 weakMap、weakSet。

闭包会导致内存泄露吗?​

顺便说一个我在了解垃圾回收之前对闭包的误解。

闭包会导致内存泄露吗?正确的答案是不会。

内存泄露是指你「用不到」(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量就是我们需要的变量,不能说是内存泄露。

这个误解是如何来的? 因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。 这是 IE 的问题,不是闭包的问题。 参考这篇

浏览器数据库 IndexedDB​

  • IndexedDB 就是浏览器提供的本地数据库
  • 在用户的浏览器内持久化存储数据的方法
  • 允许储存大量数据

浏览器缓存方案​

  • 强缓存
  • 协商缓存
  • localStorage与sessionStorage
  • IndexedDB浏览器数据库,存储空间大小是根据你当前硬盘内存来决定

浏览器的SameSite​

Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF【跨站请求伪造】 攻击和用户追踪http

浏览器如何识别资源类型​

  • 浏览器会通过 HTTP响应头中的 Content-Type字段,来确定资源的类型
    • Content-Type表示内容类型

如

  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml : XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式