面试经典题汇总📝

输入网址之后发生了什么?

我们在浏览器输入网址之后发生了什么,为什么我们能收到这个页面呢?

路径纠错

第一步❗️路径纠错

我们输入的路径可能有错,也可能缺少协议等东西,就比如我们输入了www..baidu.com,那么浏览器就会自动加上协议,变成http://www.baidu.com,路径补全后变成http://www.baidu.com/

DNS解析

第二步❗️DNS解析
DNS解析,就是把域名解析成IP地址,比如www.baidu.com,那么DNS解析之后,就会变成192.168.3.11

❗️这里需要注意DNS缓存和DNS载荷均衡❗️
  1. DNS缓存
    • 本地缓存
    • 浏览器缓存
    • 系统缓存
  2. DNS载荷均衡 我们知道`DNS解析`后会获取到一个IP地址,这个地址对应网站服务器地址;但是一个大公司可能有上千台服务器,那么返回的到底是哪台服务器呢? 这里就需要到DNS负载均衡了,所谓的负载均衡是**根据我们的地理位置距离服务器的距离**来决定解析出的IP地址,这样就很好的分散了服务器的压力,提高我们的访问速度。

TCP连接

第三步❗️TCP连接
简单来说,TCP连接就是我们为发送和接受数据建立的通道,而TCP连接的建立需要三次握手和四次挥手。

三次握手

  1. 客户端向服务端发送一个SYN包
  2. 服务端在接收到SYN包之后,向客户端发送一个SYN+ACK包
  3. 客户端在接收到SYN+ACK包之后,向服务端发送一个ACK包

经过这三次握手,TCP连接就建立起来了。

发送HTTP请求

第四步❗️发送HTTP请求
客户端向服务端发送一个HTTP请求,请求包括请求行,请求头,请求体

  • 请求行
    • 请求方法: GET/POST/PUT/DELETE
    • 请求路径
  • 请求头
  • 请求体(GET请求没有)

服务端响应数据

第五步❗️服务端响应数据
服务端接收到http请求后会返回一个http响应:

  • 状态行
    • 响应码
  • 响应头
    • content-type: text/html;charset=utf-8
  • 响应体

渲染

关于浏览器渲染可以看这篇博客浏览器渲染原理

断开连接

第六步❗️断开连接

js

&& 和 ||

数据1 && 数据2 === > 前后依次进行布尔判断

数据1 || 数据2 === > 前后依次进行布尔判断

最终结果都是返回最后一步判定的数据。

例:

condole.log(2 && 3) // 3

console.log(2 || 3) // 2

常见应用:

  1. 赋默认值
const a = obj.a || 'default'
  1. 函数的调用
const resault = obj.func && obj.func() 

深度克隆

首先明确一下 javascript 的8种数据类型:

  1. 基本类型:stringnumberundefinedbooleannullsymbolbigint
  2. 引用类型:object
const deepClone = (val) => {
// 复杂类型
// 数组
if (Array.isArray(val)) {
var clone = []
for (let i = 0; i < val.length; i++) {
clone[i] = deepClone(val[i])
}
}

if (typeof val === 'object' && val !== null) {
var cloneObj = {}
for (const key in val) {
cloneObj[key] = deepClone(val[key])
}
}


// 基本类型
return val
}

console.log(deepClone([1, 2, [3, 4], 5])); // [1, 2, [3, 4], 5]
console.log(deepClone({ a: 1, b: 2, c: { d: 3, e: 4 } })); // { a: 1, b: 2, c: { d: 3, e: 4 } }

为什么要有虚拟DOM?

与原生js比对,现在流行的框架如ReactVue或者Angular都使用了虚拟DOM的设计。当数据发生改变时,会先生成新的虚拟DOM树,经过与旧虚拟DOM树的比对,只更新改变的部分,这极大提高了渲染性能,降低了浏览器的性能浪费。更加完整的解释是这样的:

  1. 框架设计

像那些直接更新DOM的框架,它们的颗粒度对齐到**DOM**节点,当数据发生改变的时候,只更新需要更新的节点;

而对于Vue这些框架,它们的颗粒度对齐到组件,当数据更新时,整个组件都要重新渲染;如果组件中DOM过多的话,就可能会造成浏览器的多次重排、重绘,渲染性能浪费。引入虚拟DOM之后就很大程度的减轻了浏览器的负担。

  1. 运行环境

DOM能在浏览器或node模拟环境中运行,但是在移动端就不能运行(移动端需要的是系统的原生组件);

但是虚拟DOM会将组件结构生成**js对象**,依据判断出的运行环境给出相应的DOM节点或者原生组件,实现**一套代码,多端复用**(像React Native等)。

js事件循环

首先要知道js代码的核心是:**单线程和异步任务队列**

事件循环的核心部分是:调用栈任务队列(包含宏任务队列和微任务队列)

  1. **调用栈****:**同步代码的执行区。
  • 第一个宏任务默认为script整块代码,同步执行该代码块,依次放入调用栈,遇到异步任务如setTimeoutPromise.then()等,分别放入微任务和宏任务队列;
  • 调用栈为空时,执行微任务队列内容直至清空;
  1. **任务队列**:
  • 宏任务: 主要是浏览器或者Nodejs发起的任务。
    • script整块代码;
    • setTimeout、setInterval等
    • I/O操作(如文件读写、网络请求)
    • 事件操作(如click、resize、scroll)
    • UI渲染
  • 微任务:主要是js引擎发起的任务。
    • Promise.then/catch/finally
    • queneMicroTask(显式微任务)
    • MutationObserver(DOM变化监听器)

事件循环过程:

  1. 第一个宏任务默认为script整块代码,之后默认去除宏任务队列中最早放入的一个执行,同步执行该代码块,依次放入调用栈,遇到异步任务如setTimeoutPromise.then()等,分别放入微任务和宏任务队列;
  2. 调用栈为空时,执行微任务队列内容,如果微任务中嵌套微任务,那么就将嵌套的微任务再次放入微任务队列,直至清空;
  3. UI渲染:在微任务清空完,下个宏任务执行前,若有任务引起了DOM的变化,就会引起浏览器的重绘重排;
  4. 当UI渲染结束后,本次事件循环结束,执行下个宏任务即为下次事件循环开始;
  5. 事件循环是个无限循环的过程,当调用栈和任务队列为空,那么循环结束。