### 网页加载渲染过程
#### 加载资源的过程
* DNS 解析:域名 -> IP 地址
* 浏览器根据 IP 地址向服务器发起 http 请求
* 服务器处理 http 请求,并返回给浏览器
#### 渲染过程
* 根据 HTML 代码生成 DOM Tree;DOM:document object model
* 根据 CSS 代码生成 CSSOM
* 将 DOM Tree 和 CSSOM 整合形成 Render Tree(渲染树)
* 根据 Render Tree 渲染页面
* 遇到 `<script>` 则暂停渲染,优先加载并执行 JS 代码,完成在继续
* 直至 Render Tree 渲染完成
##### window.onload 和 DOMContentLoaded区别
```javascript
document.addEventListener('DOMContentLoaded', function () {
// DOM 渲染完即可执行,此时图片、视频可能还没有加载完成
console.log('1')
})
window.addEventListener('load', function () {
// 页面的全部资源加载完,才会执行,包括图片、视频等
console.log('2')
})
```
### 性能优化
#### 性能优化原则
* 多使用内存、缓存或其他方法
* 减少 CPU 计算量,减少网络加载耗时
* (适用于所有编程的性能优化---空间换时间)
#### 从何入手
* 让加载更快
* 减少资源代码:压缩代码
* 减少访问次数:合并代码,SSR 服务端渲染,缓存
* 使用更快的网络:CDN
* 让渲染更快
* CSS 放 head ,JS 放在 body 最下面
* 今早开始执行 JS ,用 DOMContentLoaded 触发
* 懒加载(图片懒加载,上滑加载更多)
* 对 DOM 查询进行缓存
* 频繁 DOM 操作,合并到一起插入 DOM 结构
* 节流 throttle 防抖 debounce
* SSR--Server-Side Rendering
* 服务端渲染:将网页和数据一起加载,一起渲染
* 非 SSR (前后端分离):先加载网页,再加载数据,再渲染数据
#### 防抖 debounce
> 监听一个输入框,文字变化后触发 change 事件;直接用 keyup 事件,则会频繁触发 change 事件;
>
> 防抖:用户输入结束或暂停时,才会触发 change 事件。
>
> 扩展阅读:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/5
```javascript
// 纯 JS 中写法
let timer = null
function debounce() { // debounce 函数会被快速多次执行
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(()=>{
// 业务代码
// 清空定时器
timeer = null
},500)
}
```
```javascript
// 封装一下,使其实用性更强
function debounce(fn, dealy = 500) {
let timer = null
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, dealy)
}
}
// 使用
function demo() {
// 业务函数
console.log('业务函数')
}
input1.addEventListener('keyup', debounce(demo, 300))
```
#### 节流 throttle
> 拖拽一个元素时,要随时按到该元素被拖拽的位置;直接用 drag 事件,则会频繁触发,很容易导致卡顿;节流:无论拖拽速度多快,都会每隔 100ms 触发一次
```html
<!-- 基础写法 -->
<div id="div1" draggable="true">可拖拽</div>
<script>
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)
})
</script>
```
```javascript
// 封装一下
function throttle(fn, frequency = 100) {
let timer = null
return function () {
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, frequency)
}
}
// 使用
const div1 = document.getElementById('div1')
div1.addEventListener(
'drag',
throttle((event) => {
console.log(event.offsetX, event.offsetY)
})
)
```
### 安全
扩展阅读:[前端安全系列(一):如何防止XSS攻击?](https://tech.meituan.com/2018/09/27/fe-security.html)
#### XSS 跨站请求攻击
> 一个博客网站,我发表一篇博客,其中嵌入 `<script>` 脚本;脚本内容:获取 cookie,发送到我的服务器(服务器 配合跨域);发布这篇博客,有人查看它,我轻松收割访问者的 cookie
* XSS 预防
![image-20210311105909688](https://image.mdashen.com/pic/image-20210311105909688.png)
#### XSRF 跨站请求伪造
![image-20210311110220784](https://image.mdashen.com/pic/image-20210311110220784.png)
![image-20210311110242575](https://image.mdashen.com/pic/image-20210311110242575.png)
* XSRF 预防
![image-20210311110336823](https://image.mdashen.com/pic/image-20210311110336823.png)