🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 网页加载渲染过程 #### 加载资源的过程 * 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)