2025年了,再被面试官问到这些问题就该自信吟唱了 —— 浏览器篇

182 阅读10分钟

写这篇文章主要记录一些自己在面试过程中被问到的高频问题以及自己的一些理解,因为是面试题,难免会写得比较无聊,在努力改进,本文结合目录食用更佳。

如果有写的不准确的地方,欢迎评论区指出~


Q:浏览器相关问题

浏览器事件循环(Event Loop)

JavaScript 运行时环境(如浏览器)处理异步操作和回调机制的核心部分。它确保了在单线程环境中,即使存在大量的异步操作,代码也能有序且高效地执行。

浏览器事件循环的主要步骤和机制:

  1. 执行栈(Execution Stack):
    1. 当浏览器加载一个页面时,JavaScript 引擎会创建一个全局执行上下文,并将其推入执行栈。
    2. 当调用函数时,会为该函数创建一个新的执行上下文,并将其推入执行栈。
    3. 执行栈中的代码同步执行,直到执行完毕或遇到异步操作。
  2. 任务队列(Task Queue):
    1. 浏览器为异步操作维护了一个或多个任务队列。这些队列用于存放待处理的任务(通常是回调函数)。
    2. 当一个异步操作(如setTimeoutAJAX请求、用户交互等)完成时,它的回调函数会被放入任务队列中等待执行。
  3. 事件循环
    1. 当执行栈为空时(即没有更多的同步代码需要执行),事件循环会查看任务队列。
    2. 如果任务队列中有任务,事件循环会取出一个任务并将其放入执行栈中执行。
    3. 执行完毕后,事件循环再次查看任务队列,取出下一个任务执行,如此循环往复。
  4. 宏任务(MacroTask)与微任务(MicroTask):
    1. 任务队列实际上分为宏任务队列和微任务队列。
    2. 宏任务包括script(整体代码)、setTimeoutsetIntervalI/O、UI渲染等。
    3. 微任务包括Promise的回调、process.nextTick(Node.js中)、MutationObserver 等。
    4. 在每个事件循环的迭代中,首先执行栈中的同步代码,然后执行所有的微任务,最后才执行一个宏任务。在下一个迭代中,再次执行所有的微任务,然后再执行下一个宏任务,依此类推。

代码示例:

console.log('script start');
 
setTimeout(function() {
  console.log('setTimeout');
}, 0);
 
Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});
console.log('script end');

//log打印为:
    script start、
    script end、
    promise1、
    promise2、
    setTimeout

以上代码执行帧动画可以查看 Tasks, microtasks, queues and schedules

process.nextTickprocess.nextTick 允许你将一个回调函数推迟到当前事件循环的迭代结束之前执行。这意味着,无论当前正在处理什么操作(例如 I/O 操作或定时器回调),process.nextTick 注册的回调函数都会在当前事件循环迭代结束之前优先执行。因此,它的执行优先级非常高。

PromisePromise 是另一种处理异步操作的方式。当一个 Promiseresolvereject 时,它的回调函数会被放入微任务队列中。微任务队列会在每个事件循环迭代的末尾被清空,这意味着 Promise 的回调函数会在当前事件循环迭代的所有同步代码和 process.nextTick 回调之后执行。

因此,根据这些机制的特点,我们可以得出以下执行顺序:

  1. 首先执行同步代码。
  2. 然后执行 process.nextTick 注册的回调函数。
  3. 接着执行微任务队列中的 Promise 回调函数。
  4. 最后,当当前事件循环迭代结束时,进入下一个事件循环迭代,并重复上述过程。

浏览器本地存储中 cookie、localStorage 和 SessionStorage的区别

  1. 存储容量不同

    存储类型容量
    cookie一般为4KB
    localStorage一般为5MB
    sessionStorage一般为5MB
  2. 有效期不同(过期时间)

    存储类型生命周期
    cookie可以设置过期时间(ExpiresMax-Age),一旦过期就会被浏览器删除
    localStorage持久化存储,除非手动清除或用户清理浏览器缓存,否则不会失效。
    sessionStorage会话级存储,数据仅在当前标签页或窗口的会话期间有效,关闭标签页或窗口后清除。
  3. 与服务端的通信

    存储类型是否跟随HTTP请求传输
    cookie默认情况下,浏览器会将 Cookie 附加到同源 HTTP 请求头中,增加网络负载(可设置 HttpOnly 限制)
    localStorage不参与服务器端的通信,仅在客户端(即浏览器)中保存。
    sessionStorage不参与服务器端的通信,仅在客户端(即浏览器)中保存。
  4. 生成方式

    存储类型生成方式
    cookie由服务器生成。可设置失效时间。服务器通过响应头Set-Cookie传给前端
    localStorage由前端生成
    sessionStorage由前端生成
1)xxxStorage.setItem(‘key’, ‘value’);
    该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
    
(2)xxxStorage.getItem(‘key’);
    该方法接受一个键名作为参数,返回键名对应的值。
    
(3)xxxStorage.removeItem(‘key’);
    该方法接受一个键名作为参数,并把该键名从存储中删除。
    
(4)xxxStorage.clear();
    该方法会清空存储中的所有数据。
  1. 数据共享及访问权限

    存储类型访问权限
    cookie可以设置访问路径和访问域名,以控制哪些页面可以访问 cookie,在相同浏览器不同页面可共享数据
    localStorage存储的数据可以被同源(相同协议、域名和端口号)下的所有页面访问
    sessionStorage仅在同源且同一个标签页或窗口中共享,页面跳转可以共享数据,但不同标签页或窗口间无法共享

即使是同一个页面(URL 相同),如果打开在不同的标签页或窗口中,它们的 sessionStorage 数据也不会共享。

同一个标签页内的页面间跳转(如通过链接或表单提交)会共享 sessionStorage 数据,但在页面刷新时,数据仍然存在。

  1. 安全性

    存储类型安全性
    cookie设置正确的安全属性相对安全
    localStorage易受 XSS 攻击, 不适合存储敏感数据
    sessionStorage易受 XSS 攻击, 不适合存储敏感数据

cookie 综合安全属性的设置

Set-Cookie: sessionId=abc123; Secure; HttpOnly; SameSite=Strict; Domain=example.com; Path=/; Expires=Tue, 20 Jan 2025 12:00:00 GMT;
  • Secure:仅通过 HTTPS 传输。
  • HttpOnly:防止 JavaScript 窃取。
  • SameSite=Strict:防止跨站请求伪造。
  • Domain=example.com:允许主域及其子域访问。
  • Path=/:Cookie 可用于整个网站。
  • Expires:指定到期时间。

最佳实践总结:

  • 始终使用 HTTPSSecure 属性。
  • 为敏感数据的 Cookie 添加 HttpOnly,防止被 JavaScript 访问。
  • 使用 SameSite 属性防范 CSRF 攻击。
  • 限制 Cookie 的作用域(Domain 和 Path)。
  • 设置合理的有效期或让 Cookie 在会话结束时失效。

通过以上设置,可以大幅提高 Cookie 的安全性,减少被攻击利用的风险。

从输入url开始到渲染页面浏览器都做了什么

这道题也是我们的老朋友了,我们一起来回顾下吧

当用户在浏览器中输入一个 URL 并按下回车后,浏览器经历多个步骤才能渲染出页面。以下是详细的过程:

  1. URL 解析

    浏览器会解析用户输入的内容,判断是:

    • 完整的 URL(如 www.example.com)
    • 搜索关键字(如 example,未包含协议的字符串)

    如果是完整的 URL,浏览器会首先解析这个URL,判断其是否合法。如果是搜索关键字,浏览器会通过默认搜索引擎生成搜索请求。

  2. DNS 解析

    浏览器需要将域名(如 www.example.com)解析成对应的 IP 地址:

    • 本地缓存查找: 首先在浏览器缓存、操作系统缓存中查找对应的 IP 地址。
    • 递归 DNS 查询: 如果本地缓存没有命中,向 DNS 服务器递归查询,直到获取到 IP 地址。(DNS 解析的过程就是寻找哪个服务器上有请求的资源

DNS解析域名过程: 其实DNS可以看做是个数据库,记录了很多URL和对应的IP地址,这样就能用DNS解析出IP

用户在浏览器输入域名,操作系统会检查 浏览器缓存和操作系统缓存(本地的host文件) 中是否有这个网址记录,有,则从记录里找到对应的IP,完整域名解析;

没有,则接着检查本地DNS(网络配置中的"DNS服务器地址"了。操作系统会把这个域名发送给这个本地DNS服务器)是否缓存该网址记录,有,则返回解析结果,完成域名解析;

还没有,则本地DNS服务器会发送查询报文到根DNS服务器,根DNS服务器收到请求后,返回顶级DNS服务器地址(它是国际顶级域名服务器,如.com、.cn、.org等,全球只有13台左右),(根服务器发出请求,进行递归查询(DNS服务器先问根域名服务器.com域名服务器的IP地址,然后再问.com域名服务器,依次类推)

其实就是三步骤:

1、找缓存

2、找本机的hosts文件

3、找DNS服务器

  1. 建立 TCP 连接
    • 三次握手: 浏览器与目标服务器通过三次握手建立 TCP 连接。
      • 客户端发送 SYN。
      • 服务器响应 SYN-ACK。
      • 客户端发送 ACK。

如果使用了 HTTPS,还需进行额外的 TLS/SSL 握手,建立加密通道。

  1. 发送 HTTP/HTTPS 请求
  • 浏览器通过建立的连接发送 HTTP/HTTPS 请求
    • 请求方法: 通常是 GET,也可能是 POSTPUT 等。
    • 请求头: 包含必要的信息,如:
      • Host:目标主机名。
      • User-Agent:浏览器的用户代理信息。
      • Accept:客户端希望接收的内容类型。
      • Cookie:包含用户的会话信息。
    • 请求体(可选): 包含表单数据等信息(仅对于 POSTPUT 等方法)。
  1. 服务器处理请求

    服务器接收到请求后会

    • 检查请求路径和参数。
    • 根据逻辑处理数据,可能会从数据库读取内容。
    • 生成响应数据(如 HTML、CSS、JS 或 API 数据)。
    • 返回 HTTP 响应。
  2. 浏览器接收 HTTP 响应

    • 响应状态码: 如 200(成功)、301(重定向)、404(未找到)、500(服务器错误)。
    • 响应头: 包含信息如:
      • Content-Type:响应内容类型(如 text/html)。
      • Content-Length:响应数据大小。
      • Set-Cookie:服务器设置的 Cookie。
    • 响应体: 实际的 HTML、CSS、JavaScript 或其他文件内容。
  3. 浏览器解析和渲染页面

    a. HTML 解析: 浏览器从上到下解析 HTML,构建 DOM 树。遇到外部资源(如 CSS、JS、图片)时,启动并行下载。

    b. CSS 解析:下载 CSS 文件,解析为 CSSOM 树。与 DOM 树结合,生成 渲染树。

    c. JavaScript 执行: 遇到

    d. 渲染树布局:根据渲染树计算每个元素的位置和尺寸。

    e. 分层与绘制:将页面分为多个图层(如 z-index 层叠上下文),将图层内容绘制为位图。

    f. 合成与显示:图层通过合成器合成为帧,显示在屏幕上。

  4. Http请求结束,TCP断开连接:浏览器与服务器进行四次挥手断开链接。

总结过程

  • 输入 URL
  • DNS 解析
  • 建立连接
  • 发送 HTTP 请求
  • 服务器响应
  • 浏览器解析和渲染
  • 显示页面
  • 断开连接