web前端面试高频考点——性能优化篇
# 系列文章目录
> JavaScript 知识梳理,收录了web前端面试 ==95%以上== 的高频考点,满满的干货。给你做一个高效的知识梳理,为你的面试保驾护航!
|内容| 参考链接 |
|--|--|
| HTML & CSS 篇 | [HTML & CSS 篇](https://blog.csdn.net/qq_45902692/article/details/126056763) |
| JavaScript 篇(一) | [JavaScript 篇(一)【JS的三座大山 】原型和原型链、作用域和闭包、异步](https://blog.csdn.net/qq_45902692/article/details/126077498) |
| JavaScript 篇(二) | [JavaScript 篇(二)【JS 异步进阶】](https://blog.csdn.net/qq_45902692/article/details/126123773) |
| JavaScript-Web-API 篇(一) | [JavaScript-Web-API 篇(一)DOM、BOM、事件](https://blog.csdn.net/qq_45902692/article/details/126174849) |
| JavaScript-Web-API 篇(二) | [JavaScript-Web-API 篇(二)AJAX、存储](https://blog.csdn.net/qq_45902692/article/details/126189846) |
| HTTP 篇 | [HTTP 篇](https://blog.csdn.net/qq_45902692/article/details/126213301) |
| 性能优化篇 | [性能优化篇(手写防抖、手写节流、XXS攻击、XSRF攻击)](https://blog.csdn.net/qq_45902692/article/details/126219544) |
| 经典面试题-JS篇 | [经典面试题 HTML、CSS、JavaScript篇](https://blog.csdn.net/qq_45902692/article/details/126240337) |
---
@[TOC](文章目录)
---
# 运行环境
## 一、在哪里运行
- 运行环境即浏览器(server 端有nodejs)
- 下载网页源码,渲染出页面,期间会执行若干 JS
- 要保证代码在浏览器中:稳定且高效
## 二、 网页是如何加载并渲染出来的
### 1、资源的形式
- html 代码
- 媒体文件,如图片、视频等
- JavaScript CSS
### 2、加载过程
- DNS 解析:域名 -> IP 地址
- 浏览器根据 IP地址向服务端发起 http 请求
- 服务器处理 http 请求,并返回给浏览器
### 3、渲染过程
- 根据 HTML 代码生成 DOM Tree(文档对象模型树)
- 根据 CSS 代码生成 CSSOM(CSS对象模型)
- DOM 树和 CSSOM 可以并行构建
- 将 DOM Tree 和 CSSOM 整合形成 Render Tree(渲染树)
- 根据 Render Tree 渲染页面
- 遇到 `<script>` 则暂停渲染,优先加载并执行 JS 代码,完成再继续
- 直至把 Render Tree 渲染完成
### 4、window.onload 和 DOMContentLoaded 区别
- window.onload:页面的全部资源加载完才会执行,包括图片、视频等
- DOMContentLoaded:DOM 渲染完即可执行,此时图片、视频还可能没有加载完
```javascript
window.addEventListener('load', function() {
// 页面的全部资源加载完才会执行,包括图片、视频等
})
document.addEventListener('DOMContentLoaded', function() {
// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})
```
## 二、性能优化
### 1、性能优化原则
- 多使用内存、缓存或其他方法
- 减少CPU 计算量,减少网络加载耗时
- 用空间换时间
### 2、性能优化 — 让加载更快
- 减少资源体积:压缩代码
- 减少访问次数:合并代码,SSR 服务器端渲染,缓存
- 使用更快的网络:CDN(分布在不同区域的边缘节点服务器群组成的分布式网络)
### 3、性能优化 — 让渲染更快
- CSS 放在 head,JS 放在 body 最下面
- 尽早开始执行 JS,用 DOMContentLoaded 触发
- 懒加载(图片懒加载,上滑加载更多)
- 对 DOM 查询进行缓存
- 频繁 DOM 操作,合并到一起插入 DOM 结构
- 节流 throttle 防抖 debounce
### 4、前端性能优化示例
**资源合并:**
```javascript
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
// 合并为
<script src="abc.js"></script>
```
**缓存:**
- 静态资源加 hash 后缀,根据文件内容计算 hash(webpack中的配置)
- 文件内容不变,则 hash 不变,则 url 不变
- url 和文件不变,则会自动触发 http 缓存机制,返回 304
**CDN:**
**SSR:**
- 服务器端渲染:将网页和数据一起加载,一起渲染
- 非 SSR(前后端分离):先加载网页,再加载数据,再渲染数据
- 早先的 JSP ASP PHP,现在的 vue react SSR
**懒加载:**
先给一个容易加载的图片,等加载完成后把真正的图片展现出来
```javascript
<img id="img1" src="preview.png" data-realsrc="abc.png">
let img1 = document.getElementById('img1')
img1.src = img1.getAttribute('data-realsrc')
```
**缓存 DOM 查询:**
![在这里插入图片描述](https://img-blog.csdnimg.cn/5685cfcd9245456991d9bfcf681256f1.png)
**多个 DOM 操作一起插入到 DOM 结构:**
![在这里插入图片描述](https://img-blog.csdnimg.cn/f3c19cf6e99c47f780bbdf26ba9aa19f.png)
**尽早开始 JS 执行:**
```javascript
window.addEventListener('load', function() {
// 页面的全部资源加载完才会执行,包括图片、视频等
})
document.addEventListener('DOMContentLoaded', function() {
// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})
```
### 5、防抖 debounce
- 监听一个输入框的,文字变化后触发 change 事件
- 直接用 keyup 事件,则会频繁触发 change 事件
- 防抖:用户输入结束或暂停时,才会触发 change 事件
**示例:input 框的防抖**
```javascript
<input type="text" id="input1">
let input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup', function(value) {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
// 模拟触发 change 事件
console.log(input1.value)
// 清空定时器
timer = null
}, 500)
})
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/7baf4d4b979e4a49905666dfae4c96d4.png)
**封装防抖 debounce 函数:**
```javascript
<input type="text" id="input1">
let input1 = document.getElementById('input1')
// 防抖
function debounce(fn, delay = 500) {
// timer 是闭包中的
let timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
input1.addEventListener('keyup', debounce(() => {
console.log(input1.value)
}, 1000))
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/78391ca6b52f4a539e197faa56a2b906.png)
### 6、节流 throttle
- 拖拽一个元素时,要随时拿到该元素被拖拽的位置
- 直接用 drag 事件,则会频繁触发,很容易导致卡顿
- 节流:无论拖拽速度多快,都会每隔 xxxms 触发一次
**示例:拖拽一个 div**
```javascript
#div1 {
border: 1px solid #ccc;
width: 200px;
height: 100px;
}
<div id="div1" draggable="true">可拖拽</div>
const div1 = document.getElementById('div1')
let timer = null
div1.addEventListener('drag', function (event) {
if(timer) {
return
}
timer = setTimeout(() => {
console.log(event.offsetX, event.offsetY)
timer = null
}, 100)
})
```
**封装节流 throttle 函数:**
```javascript
#div1 {
border: 1px solid #ccc;
width: 200px;
height: 100px;
}
<div id="div1" draggable="true">可拖拽</div>
const div1 = document.getElementById('div1')
function throttle(fn, delay = 100) {
let timer = null
return function() {
if(timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
div1.addEventListener('drag', throttle(function (event) {
console.log(event.offsetX, event.offsetY)
},))
```
## 三、常见的 web 前端攻击方式
- XSS 跨站请求攻击
- XSRF 跨站请求伪造
### 1、XXS 攻击
- 一个博客网站,我发表一篇博客,其中嵌入 `<script></script>` 脚本
- 脚本内容:获取 cookie,发送到我的服务器(服务器配合跨域)
- 发表这篇博客,有人查看它,我轻松收割访问者的 cookie
### 2、XXS 预防
- 替换特殊字符,如 ==<== 变为 `<` ==>== 变为 `>`
- `<script>` 变为 `<script>` 直接显示,而不会作为脚本执行
- 前端要替换,后端也要替换,都做更保险
示例:脚本不会执行,直接在页面显示
```javascript
<script>alert(document.cookie)<script>
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/2b3aeb91ef3c49c1b8945987b97f48a3.png)
### 3、XSRF 攻击
- 我向你发送一封电子邮件,邮件标题很吸引人
- 但邮件正文隐藏着 `<img src="xxx.com/pay?id=200" />`
- 你一查看邮件,就帮我购买了 id 是 200 的商品
### 4、XSRF 预防
- 使用 post 接口
- 增加验证,例如密码、短信验证码、指纹等
#JavaScript#
> JavaScript 知识梳理,收录了web前端面试 ==95%以上== 的高频考点,满满的干货。给你做一个高效的知识梳理,为你的面试保驾护航!
|内容| 参考链接 |
|--|--|
| HTML & CSS 篇 | [HTML & CSS 篇](https://blog.csdn.net/qq_45902692/article/details/126056763) |
| JavaScript 篇(一) | [JavaScript 篇(一)【JS的三座大山 】原型和原型链、作用域和闭包、异步](https://blog.csdn.net/qq_45902692/article/details/126077498) |
| JavaScript 篇(二) | [JavaScript 篇(二)【JS 异步进阶】](https://blog.csdn.net/qq_45902692/article/details/126123773) |
| JavaScript-Web-API 篇(一) | [JavaScript-Web-API 篇(一)DOM、BOM、事件](https://blog.csdn.net/qq_45902692/article/details/126174849) |
| JavaScript-Web-API 篇(二) | [JavaScript-Web-API 篇(二)AJAX、存储](https://blog.csdn.net/qq_45902692/article/details/126189846) |
| HTTP 篇 | [HTTP 篇](https://blog.csdn.net/qq_45902692/article/details/126213301) |
| 性能优化篇 | [性能优化篇(手写防抖、手写节流、XXS攻击、XSRF攻击)](https://blog.csdn.net/qq_45902692/article/details/126219544) |
| 经典面试题-JS篇 | [经典面试题 HTML、CSS、JavaScript篇](https://blog.csdn.net/qq_45902692/article/details/126240337) |
---
@[TOC](文章目录)
---
# 运行环境
## 一、在哪里运行
- 运行环境即浏览器(server 端有nodejs)
- 下载网页源码,渲染出页面,期间会执行若干 JS
- 要保证代码在浏览器中:稳定且高效
## 二、 网页是如何加载并渲染出来的
### 1、资源的形式
- html 代码
- 媒体文件,如图片、视频等
- JavaScript CSS
### 2、加载过程
- DNS 解析:域名 -> IP 地址
- 浏览器根据 IP地址向服务端发起 http 请求
- 服务器处理 http 请求,并返回给浏览器
### 3、渲染过程
- 根据 HTML 代码生成 DOM Tree(文档对象模型树)
- 根据 CSS 代码生成 CSSOM(CSS对象模型)
- DOM 树和 CSSOM 可以并行构建
- 将 DOM Tree 和 CSSOM 整合形成 Render Tree(渲染树)
- 根据 Render Tree 渲染页面
- 遇到 `<script>` 则暂停渲染,优先加载并执行 JS 代码,完成再继续
- 直至把 Render Tree 渲染完成
### 4、window.onload 和 DOMContentLoaded 区别
- window.onload:页面的全部资源加载完才会执行,包括图片、视频等
- DOMContentLoaded:DOM 渲染完即可执行,此时图片、视频还可能没有加载完
```javascript
window.addEventListener('load', function() {
// 页面的全部资源加载完才会执行,包括图片、视频等
})
document.addEventListener('DOMContentLoaded', function() {
// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})
```
## 二、性能优化
### 1、性能优化原则
- 多使用内存、缓存或其他方法
- 减少CPU 计算量,减少网络加载耗时
- 用空间换时间
### 2、性能优化 — 让加载更快
- 减少资源体积:压缩代码
- 减少访问次数:合并代码,SSR 服务器端渲染,缓存
- 使用更快的网络:CDN(分布在不同区域的边缘节点服务器群组成的分布式网络)
### 3、性能优化 — 让渲染更快
- CSS 放在 head,JS 放在 body 最下面
- 尽早开始执行 JS,用 DOMContentLoaded 触发
- 懒加载(图片懒加载,上滑加载更多)
- 对 DOM 查询进行缓存
- 频繁 DOM 操作,合并到一起插入 DOM 结构
- 节流 throttle 防抖 debounce
### 4、前端性能优化示例
**资源合并:**
```javascript
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
// 合并为
<script src="abc.js"></script>
```
**缓存:**
- 静态资源加 hash 后缀,根据文件内容计算 hash(webpack中的配置)
- 文件内容不变,则 hash 不变,则 url 不变
- url 和文件不变,则会自动触发 http 缓存机制,返回 304
**CDN:**
**SSR:**
- 服务器端渲染:将网页和数据一起加载,一起渲染
- 非 SSR(前后端分离):先加载网页,再加载数据,再渲染数据
- 早先的 JSP ASP PHP,现在的 vue react SSR
**懒加载:**
先给一个容易加载的图片,等加载完成后把真正的图片展现出来
```javascript
<img id="img1" src="preview.png" data-realsrc="abc.png">
let img1 = document.getElementById('img1')
img1.src = img1.getAttribute('data-realsrc')
```
**缓存 DOM 查询:**
![在这里插入图片描述](https://img-blog.csdnimg.cn/5685cfcd9245456991d9bfcf681256f1.png)
**多个 DOM 操作一起插入到 DOM 结构:**
![在这里插入图片描述](https://img-blog.csdnimg.cn/f3c19cf6e99c47f780bbdf26ba9aa19f.png)
**尽早开始 JS 执行:**
```javascript
window.addEventListener('load', function() {
// 页面的全部资源加载完才会执行,包括图片、视频等
})
document.addEventListener('DOMContentLoaded', function() {
// DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})
```
### 5、防抖 debounce
- 监听一个输入框的,文字变化后触发 change 事件
- 直接用 keyup 事件,则会频繁触发 change 事件
- 防抖:用户输入结束或暂停时,才会触发 change 事件
**示例:input 框的防抖**
```javascript
<input type="text" id="input1">
let input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup', function(value) {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
// 模拟触发 change 事件
console.log(input1.value)
// 清空定时器
timer = null
}, 500)
})
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/7baf4d4b979e4a49905666dfae4c96d4.png)
**封装防抖 debounce 函数:**
```javascript
<input type="text" id="input1">
let input1 = document.getElementById('input1')
// 防抖
function debounce(fn, delay = 500) {
// timer 是闭包中的
let timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
input1.addEventListener('keyup', debounce(() => {
console.log(input1.value)
}, 1000))
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/78391ca6b52f4a539e197faa56a2b906.png)
### 6、节流 throttle
- 拖拽一个元素时,要随时拿到该元素被拖拽的位置
- 直接用 drag 事件,则会频繁触发,很容易导致卡顿
- 节流:无论拖拽速度多快,都会每隔 xxxms 触发一次
**示例:拖拽一个 div**
```javascript
#div1 {
border: 1px solid #ccc;
width: 200px;
height: 100px;
}
<div id="div1" draggable="true">可拖拽</div>
const div1 = document.getElementById('div1')
let timer = null
div1.addEventListener('drag', function (event) {
if(timer) {
return
}
timer = setTimeout(() => {
console.log(event.offsetX, event.offsetY)
timer = null
}, 100)
})
```
**封装节流 throttle 函数:**
```javascript
#div1 {
border: 1px solid #ccc;
width: 200px;
height: 100px;
}
<div id="div1" draggable="true">可拖拽</div>
const div1 = document.getElementById('div1')
function throttle(fn, delay = 100) {
let timer = null
return function() {
if(timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
div1.addEventListener('drag', throttle(function (event) {
console.log(event.offsetX, event.offsetY)
},))
```
## 三、常见的 web 前端攻击方式
- XSS 跨站请求攻击
- XSRF 跨站请求伪造
### 1、XXS 攻击
- 一个博客网站,我发表一篇博客,其中嵌入 `<script></script>` 脚本
- 脚本内容:获取 cookie,发送到我的服务器(服务器配合跨域)
- 发表这篇博客,有人查看它,我轻松收割访问者的 cookie
### 2、XXS 预防
- 替换特殊字符,如 ==<== 变为 `<` ==>== 变为 `>`
- `<script>` 变为 `<script>` 直接显示,而不会作为脚本执行
- 前端要替换,后端也要替换,都做更保险
示例:脚本不会执行,直接在页面显示
```javascript
<script>alert(document.cookie)<script>
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/2b3aeb91ef3c49c1b8945987b97f48a3.png)
### 3、XSRF 攻击
- 我向你发送一封电子邮件,邮件标题很吸引人
- 但邮件正文隐藏着 `<img src="xxx.com/pay?id=200" />`
- 你一查看邮件,就帮我购买了 id 是 200 的商品
### 4、XSRF 预防
- 使用 post 接口
- 增加验证,例如密码、短信验证码、指纹等
#JavaScript#