# 4.浏览器

# 1.从输入URL到页面展示,这中间发生了什么?

  • 1.本地缓存

首先当输入完URL,浏览器会根据这个url去查找本地缓存中是否有对应的资源,如果有的话就直接从缓存里获取对应的资源进行加载,没有就进行下一步。

  • 2.DNS解析

当从本地缓存中没找到对应资源的时候,接下来就会进行DNS解析。浏览器首先需要知道该URL对应的IP地址。这是通过查询域名系统(DNS)来完成的。如果浏览器缓存或操作系统缓存中有此域的IP地址,则会直接使用;否则,它会发出一个DNS请求到DNS服务器。

  • 3.建立TCP连接

找到输入的域名对应的IP地址后,浏览器与目标服务器会建立tcp连接。这涉及到一个三次握手过程。

  • 4.发送HTTP请求

浏览器发送一个HTTP请求到服务器,请求指定的资源。 如果是HTTPS请求,还会涉及到TLS/SSL握手过程来加密通信内容。

  • 5.服务器处理请求并返回HTTP响应

服务器处理来自浏览器的请求,这可能涉及到查询数据库、处理应用逻辑等。 服务器生成一个HTTP响应并发送回浏览器。

  • 6.浏览器处理响应内容

浏览器开始解析服务器返回的HTML内容。 解析过程中,浏览器可能会发现需要额外资源(如CSS、JavaScript、图像等),这将触发额外的HTTP请求。

  • 7.构建DOM树

浏览器开始解析HTML内容并构建DOM树。 因为浏览器无法直接理解和使用html,所以需要将html转换成浏览器能理解的结构————DOM树。

  • 8.CSS处理和构建渲染树

并行于DOM树的构建,浏览器会解析CSS并与DOM结合,生成渲染树。 渲染树包含页面上要显示的所有元素及其样式信息。

  • 9.JavaScript处理:

如果HTML中有JavaScript,它可能会通过DOM API或CSSOM API修改页面结构或样式。 JavaScript的执行可能会延迟渲染。

  • 10.布局:

浏览器开始计算渲染树中每个节点在页面上的确切位置和大小。这个过程通常被称为“布局”或“重排”。

  • 11.绘制:

根据渲染树和布局信息,浏览器开始绘制页面上的每个元素。这个过程被称为“绘制”或“重绘”。

  • 12.显示完成的页面:

在所有必要的脚本都被执行并且所有的资源都被下载和渲染后,页面最终会在浏览器中完全显示出来。

# 2.Cookies、LocalStorage、SessionStorage、IndexedDB有什么区别?

# 1.Cookies

  • 1.小型数据存储,最多4KB

  • 2.通常用于保存用户的登录信息、个性化设置等

  • 3.支持设置过期时间

  • 4.会话 Cookie:如果创建一个 Cookie 时没有指定过期时间,它就是会话 Cookie。。会话 Cookie仅在浏览器会话期间有效,当浏览器完全关闭后会被删除。如果你只是关闭一个标签但浏览器仍在运行,会话 Cookies 通常会保持有效。

  • 5.持久 Cookies:这些 Cookies 通过设置 Expires 或 Max-Age 属性,有一个明确的过期时间。即使关闭浏览器或电脑,这些 Cookies 也会保留在浏览器中,直到达到设定的过期时间或被手动删除。

# 2.LocalStorage

  • 1.可以存储大约5MB的数据,远大于Cookie。

  • 2.持久存储:除非用户或网页清除。

  • 3.主要用于存储不经常更改的信息,如用户设置或草稿内容。

# 3.SessionStorage:会话存储

  • 1.跟LocalStorage储存空间差不多大

  • 2.会话存储:与LocalStorage不同的是,存储在SessionStorage的数据在页面会话结束时(如关闭页面或标签页)会被清除

  • 3.适用于需要临时存储数据的场景,如表单填写过程中的数据

# 4.IndexedDB

  • 1.浏览器提供的完整数据库系统

  • 2.用于存储大量数据,如离线应用数据或大型数据集

# 3.强缓存和协商缓存

# 1.强缓存

  • 1.强缓存不会发送请求到服务器,而是直接从客户端缓存中读取资源。主要通过以下两个HTTP响应头实现:

  • 2.Expires:设置一个具体的过期时间点。例如:Expires: Wed, 21 Oct 2021 07:28:00 GMT。不过这种方法存在时区和本地时间不同步的问题。

  • 2.Cache-Control:更为灵活的方式,指定一个相对的时间长度。例如:Cache-Control: max-age=3600 表示资源在3600秒(1小时)内有效。

# 2.协商缓存

  • 1.协商缓存:浏览器会带上之前缓存中保存的头信息,向服务器发送请求,由服务器判断是否使用缓存。主要通过以下头部字段实现:

  • 2.Last-Modified:表示资源上次更改的时间。浏览器在再次请求时会带上If-Modified-Since,值为上次的Last-Modified值。服务器通过比较来决定是否发送新的资源内容,或者返回304,表示资源未修改,可以使用本地缓存。

  • 3.ETag:是服务器为每个资源生成的唯一标识符。浏览器再次请求时会带上If-None-Match,其值为上次的ETag值。服务器比对ETag,如果相同则返回304,表示资源未修改。

# 拓展:

  • 1.http缓存问题:我改了一个文件,contenthash变了,我部署到服务器了,可是这个时候浏览器用的还是之前的html文件,该如何解决?

html文件设置使用协商缓存。

# 4.简要解释⼀下 301, 302, 304 的区别 ?

  • 1.301 用于永久重定向,表示资源已经永久移至新位置。

  • 2.302 用于临时重定向,表示资源临时位于另一位置。

  • 3.304 用于缓存控制,表示资源未修改,可以使用本地缓存。

# 5.前端项目中的性能优化?

  • 1.减少资源大小和请求数:打包的时候使用工具压缩CSS、JS和HTML文件,压缩图像或选择更适当的格式,例如:WebP

  • 2.使用缓存:正确的缓存相应的文件,利用好强缓存与协商缓存

  • 3.优化JS执行:避免长时间运行JS任务,一直占用主线程,对于复杂的计算,考虑使用Web Worker

  • 4.减少dom操作:减少重排和重绘,批量更新dom或采用虚拟dom的技术

  • 5.根据业务需要,可以使用CDN的依赖使用CDN,减少加载时间

  • 6.移除不必要的第三方库和依赖,提高性能

# 6.V8内存回收策略?

  • 1 标记清除:如何确定哪些内存需要回收,哪些内存不需要回收

  • 2 引用计数:跟踪记录每个值被引用的次数

V8采用了新生代的垃圾回收算法,将内存分为两个生代:新生代(new generation)和老生代(old generation)。

新生代特点:大多数的对象被分配在这里,这个区域很小但是垃圾回特别频繁。

老生代特点:老生代所保存的对象大多数是生存周期很长的甚至是常驻内存的对象,而且老生代占用的内存较多。

参考文章,V8引擎详细的垃圾回收 (opens new window)

首先说到垃圾回收,就要说一下JS存储数据的方式,JS中的数据类型其实是分为两类的,一类是原始数据类型,另一类就是引用类型,然后JS中的原始类型是存在栈空间中的,而引用类型是存在堆空间中的,栈空间中存了一个引用地址,然后通过这个引用地址去使用引用类型。然后对于栈空间中的垃圾数据,回收的方法是通过一个ESP指针去移动标识哪些内容是否有用,没用的就直接抹掉。而堆空间中的垃圾回收要比栈空间中的垃圾回收更为复杂,说到堆空间里的垃圾回收,我们先要说一下代际假说,这个假说有两个特点,一个特点是有些对象生存时间很短,在分配内存没多久就变得不可访问了,第二个特点是有些对象会活的很久。在这个假说的基础上,V8进行了垃圾回收的实现。首先V8引擎将堆空间分为新生代区域和老生代区域,然后新生代区域主要存储生存时间短的对象,而老生代区域存储的是生存时间长的对象。然后垃圾回收也通过2个垃圾回收器进行回收,一个副垃圾回收器负责新生代区域的垃圾回收,一个主垃圾回收器负责老生代区域的垃圾回收。新生代区域的垃圾回收,主要是将新生代区域拆分成两个区域,一个对象区域,一个空闲区域,在对象区域中对活动对象进行标记,然后将这些活动对象复制到空闲区域,然后将空闲区域和对象区域反转,然后进行垃圾回收。老生代区域的垃圾回收是通过主垃圾回收器进行的,因为老生代区域里的对象比较大,所以不能像新生代区域那样采用scavenge算法,因为复制活动对象是需要时间的,因为老生代区域里的对象比较大,复制时间会比较长,所以老生代区域采用标记-清除的方法进行垃圾回收,对不活动对象进行标记,然后标记完成之后将不活动对象全部清理掉。但是这种方法会导致内存空间里存在内存碎片,所以还有一种清理方法就是标记-整理的清理方法,基本上跟上一种方法差不多,不过清理的时候,会将活动对象全部放到一端,清除端之外的内存,这样就不存在内存碎片了。然后这里面还有一个机制就是晋升机制,当一个对象在新生代里经过2次垃圾回收还存在的话就会被自动晋升放到老生代区域中。最后就是在执行垃圾回收的过程中,因为JS是单线程运行的,所以进行垃圾回收的时候需要停下js脚本的运行工作,这样如果js垃圾回收时间较长的话,那么JS脚本如果正在执行动画,那就会卡顿,所以V8对将一个垃圾回收过程拆成了很多小的任务,和js脚本穿插执行,这样就不会有卡顿的感觉了,JS的垃圾回收机制基本是这样。