前端性能优化—网页加载过程、性能优化方法、防抖和节流

  • 一、网页加载过程
    • 1、加载资源的形式
    • 2、加载资源的过程
    • 3、渲染页面的过程
    • 4、关于window.onload 和 DOMContentLoaded
  • 二、性能优化
    • 1、性能优化原则
    • 2、性能优化的方法
    • 3、让加载更快
    • 4、让渲染更快
  • 三、防抖和节流
    • 1、防抖 debounce
    • 2、节流 throttle
  • 四、写在最后

平常我们在加载网页的时候,首先需要先加载网页代码,之后渲染出页面,在这个期间会执行若干个 JS 。那么,如果想要让网页呈现速度和渲染速度快,我们就得保证我们的代码在浏览器这个运行环境当中稳定且高效。这就谈到一个前端性能优化的问题。

在下面这篇文章,将讲解关于前端性能优化的一些常见问题。

一、网页加载过程

1、加载资源的形式

网页需要加载的资源,一般包括以下内容:

  • html 代码;
  • 媒体文件,如图片、视频等;
  • javascriptcss

2、加载资源的过程

加载资源的过程需要经过以下几个步骤:

  • DNS 解析:域名 -> IP 地址。
  • 浏览器根据 IP 地址向服务器发起 http 请求。
  • 服务器处理 http 请求,并返回给浏览器。

3、渲染页面的过程

渲染过程 - 1

  • 根据 HTML 代码生成 DOM Tree
  • 根据 CSS 代码生成 CSSOM
  • DOM TreeCSSOM 整合形成 Render Tree

渲染过程 - 2

  • 根据 Render Tree 渲染页面;
  • 遇到 <script> 则暂停渲染,优先加载并执行 JS 代码,完成后再继续执行;
  • 直至把 Render Tree 渲染完成。

4、关于window.onload 和 DOMContentLoaded

window.addEventListener('load', function(){//页面的全部资源加载完才会执行,包括图片、视频等
});document.addEventListener('DOMContentLoaded', function(){//DOM 渲染完即可执行,此时图片、视频还可能没加载完 -> 尽量选择此方法
});

二、性能优化

性能优化是一个综合性的问题,永远没有标准答案,下面将从几个方面来讲解性能优化的内容。

1、性能优化原则

  • 多使用内存、缓存或其他方法。
  • 减少 CPU 计算量,减少网络加载耗时。
  • 适用于所有编程的优化方法 —— 空间换时间。

2、性能优化的方法

(1) 让加载更快

(2) 让渲染更快

3、让加载更快

(1)减少资源体积

  • 压缩代码: 可以通过压缩代码来减少资源体积,包括 js 文件、 css 文件和图片都可以进行压缩。同时服务器端 可以通过 gzip 算法来对资源进行压缩。

(2)减少访问次数

  • 合并代码: 比如说我们写了三四个文件,但通过打包可能就只剩下一个文件,并且文件里面是以一行的形式出现,或者雪碧图也算是其中一种方式。

  • SSR服务器端渲染:

    服务端把网页和数据一起加载,一起渲染。

    非SSR:先加载网页,再加载数据,再渲染数据,这个过程听起来就优点繁琐。

    早期的 JSPASPPHP,现在的 vue SSRReact SSR

  • 缓存:

    举个例子:假设有 10 个资源,如果每次请求都要请求 10 次,那这样子是非常耗时的;那如果 10 个资源中有 6 个命中了缓存,则只需要请求另外 4 个。

    那如何做缓存来达到减少访问次数呢?

    前端会在静态资源上加 hash 后缀,根据文件内容计算 hash 。当文件内容不变时,则 hashurl 都不变。此时 url 和文件不变,则会自动触发 http 缓存机制,返回 304

(3)使用更快的网络

  • 通过 CDN 来操作:

    CDN ,即内容分发网络(Content Delivery Network,简称 CDN ),是建立并覆盖在承载网之上,由分布在不同区域的边缘节点服务器群组成的分布式网络。

    CDN 就是一个反向代理,根据地域来做网络服务,主要是前端用来做静态资源加载,通常在前端项目部署的时候进行这项操作。

    我们平常所使用的 bootstrapJQuery 一般都采用 cdn 的形式。

    这里我也不是特别了解 cdn 的内容,只能才疏学浅的进行介绍。附上一篇我看完觉得比较好理解的文章,大家可以根据需求进行查看~

4、让渲染更快

(1)html、css、js和图片层面

  • css 放在 headJS 放在 body 最下面;

  • 尽早开始执行 JS ,用 DOMContentLoaded 触发;

  • 懒加载(图片懒加载,上滑加载更多)。

    <img id = "img1" src = "preview.png" data-realsrc = "abe.png"/>
    <script type = "text/javascript">let img1 = document.getElementById('img1');//把真实的图片data-realsrc赋值给预览的图片srcimg1.src = img1.getAttribute('data-realsrc');//…… 一系列逻辑操作
    </script>
    

(2)从DOM层面

  • DOM 查询进行缓存;
  • 从频繁进行 DOM 操作,变为合并到一起进行 DOM 结构插入;

注:关于DOM的性能优化我有在之前的一篇文章中讲过,在主题一的第4小点,这里不再进行细讲,大家可以根据自身需求进行查阅~

(3)防抖 debounce 和 节流 throttle

关于防抖和节流的讲解,详细见下方。

三、防抖和节流

1、防抖 debounce

(1)含义: 从频繁执行触发变为只在最后一次触发。

(2)发生场景: 监听一个输入框,如果直接用 keyup 事件,则每输入一个文字都会触发 onchange 事件,频繁执行操作。

(3)防抖解决: 用户输入结束或暂停时,才会触发 change 事件。

(4)引例阐述

假设我们现在要监听一个输入框的值,此时我们直接用 keyup 事件来实现。实现方式如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><input type="text" id="input1"><script type="text/javascript">const input1 = document.getElementById('input1');input1.addEventListener('keyup', function(){console.log(input1.value);});</script>
</body>
</html>

此时浏览器的显示效果是这样的。

大家可以发现,当我们使用 keyup 事件处理,每当我们输入一个字母时,浏览器就会频繁进行打印,这样看起来也太耗费性能了。

于是就有了防抖的解决方案,防抖通过对频繁执行的操作变为只在最后一次执行。实现方式如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><input type="text" id="input1"><script type="text/javascript">const input1 = document.getElementById('input1');let timer = null;input1.addEventListener('keyup', function(){if(timer){clearTimeout(timer);}timer = setTimeout(() => {//模拟触发 change 事件console.log(input1.value);//清空定时器timer = null;}, 500);//  console.log(input1.value);});</script>
</body>
</html>

此时浏览器的显示效果是这样的。

通过上图发现,当我们在输入框输入字母时,只在最后输入结束时控制台才打印结果出来。而不会像上面那样频繁打印,因此通过防抖,实现了把频繁执行变为了只在最后一次执行的操作。

(5)封装防抖函数

通过上面的例子,相信大家对防抖有了一个基础的了解。接下来我们通过封装函数来实现相同效果的防抖功能。具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><input type="text" id="input1"><script type="text/javascript">const 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);}, delay);}}//运用防抖函数实现input输入框触发操作input1.addEventListener('keyup', debounce(function () {console.log(input1.value);}, 600));</script>
</body>
</html>

2、节流 throttle

(1)含义: 从频繁执行触发变为每隔一段时间触发一次。

(2)发生场景: 拖拽一个元素时,直接用 drag 事件,则会频繁触发,很容易导致卡顿。

(3)节流解决: 无论拖拽速度多快,都会每隔 100ms 触发一次(这里的 100ms 不是固定值,也可设置成其它的值)。

(4)引例阐述

假设我们现在要拖拽一个元素,并且想要随时拿到该元素被拖拽的值。此时我们直接用 drag 事件来实现。实现方式如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#div1{border: 1px solid #ccc;width: 200px;height: 100px;}</style>
</head>
<body><div id = "div1" draggable="true">可拖拽</div><script type="text/javascript">const div1 = document.getElementById('div1');//用节流之前div1.addEventListener('drag', function(e) {console.log(e.offsetX, e.offsetY);})</script>
</body>
</html>

此时浏览器的显示效果是这样的。

大家可以发现,当我们使用 drag 事件处理,每当我们拖拽元素时,浏览器就会频繁进行打印,这样似乎有一点点耗费性能。

于是就有了节流的解决方案,节流通过对频繁执行的操作变为只在每隔一段时间操作。实现方式如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#div1{border: 1px solid #ccc;width: 200px;height: 100px;}</style>
</head>
<body><div id = "div1" draggable="true">可拖拽</div><script type="text/javascript">const div1 = document.getElementById('div1');// 用节流之后let timer = null;div1.addEventListener('drag', function(e){if(timer){return;}timer = setTimeout(() => {console.log(e.offsetX, e.offsetY);timer = null;}, 500);});</script>
</body>
</html>

此时浏览器的显示效果是这样的。

通过上图发现,当我们在拖拽时,不再像刚刚那样频繁打印,而是有规律的每隔 500ms 打印一次,这样子看起来就比刚刚的频繁触发要好很多了。所以,节流是通过将频繁执行改为每隔一段时间执行。

(5)封装节流函数

通过上面的例子,相信大家对节流有了一个基础的了解。接下来我们通过封装函数来实现相同效果的节流功能。具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><input type="text" id="input1"><script type="text/javascript">const input1 = document.getElementById('input1');// 封装一个节流函数function throttle(fn, delay = 500){let timer = null;return function (){if(timer){return;}timer = setTimeout(() => {fn.apply(this, arguments);timer = null;}, delay);}}//运用节流函数实现拖拽时每隔一段时间触发操作div1.addEventListener( 'drag', throttle(function(e){console.log(e.offsetX, e.offsetY);}, 200));</script>
</body>
</html>

四、写在最后

关于前端性能优化的一些基础内容就讲到这里啦!如有疑问或文章有讲的不好的地方欢迎评论区评论或私信我交流~

  • 关注公众号 星期一研究室 ,不定期分享学习干货

  • 如果这篇文章对你有用,记得点个赞加个关注再走哦~

关于前端性能优化问题,认识网页加载过程和防抖节流相关推荐

  1. 前端性能优化——如何提高页面加载速度?

    1.将样式表放在头部 首先说明一下,将样式表放在头部对于实际页面加载的时间并不能造成太大影响,但是这会减少页面首屏出现的时间,使页面内容逐步呈现,改善用户体验,防止"白屏". 我们 ...

  2. WEB前端性能优化,提高页面加载速度

    可能有人会说:网站的性能是后端工程师的事情,与前端并无多大关系.我只能说,too young too simple.事实上,只有10%~20%的最终用户响应时间是用在从Web服务器获取HTML文档并传 ...

  3. 前端性能优化学习 08 资源加载优化

    图片延迟加载 什么是延迟加载 首先来想象一个场景,当浏览一个内容丰富的网站时,比如电商的商品列表页.主流视频网站的节目列表等,由于屏幕尺寸的限制,每次只能查看到视窗中的那部分内容,而要浏览完页面所包含 ...

  4. 前端性能优化--预加载技术

    当我们谈到前端的性能时,总是会提到比如合并.压缩.缓存或者在服务器上开启gzip之类的,目的都是为了让页面加载的更快. 资源预拉取(prefetch)则是另一种性能优化的技术.通过预拉取可以告诉浏览器 ...

  5. vue 图片拖动加载 类似于地图_前端性能优化之图片懒加载(附vue自定义指令)...

    作者:lzg9527 链接:https://juejin.cn/post/6903774214780616718 在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列 ...

  6. 不加载执行js_前端性能优化:preload 预加载页面资源

    网上看到一篇来自蚂蚁金服数据体验团队的文章,觉得不错,分享给大伙:https://juejin.im/post/5a7fb09bf265da4e8e785c38 本文主要介绍preload的使用,以及 ...

  7. html src加载外部静态资源,前端性能优化2:静态资源加载与优化

    css和js的装载与执行-HTML 页面加载渲染的过程 一个网站在浏览器端是如何进行渲染的呢? 流程示意图.png HTML渲染过程的一些特点 顺序执行.并发加载(单个域名的并发数量是有限的,所以多个 ...

  8. 性能优化——图片压缩、加载和格式选择

    本文首发于政采云前端团队博客:性能优化--图片压缩.加载和格式选择 https://www.zoo.team/article/images-compress 前言 相信大家都听说过 "258 ...

  9. 小程序性能优化之页面预加载方案——让你的小程序运行如飞 进阶篇

    小程序性能优化之页面预加载方案 进阶篇 转载请注明出处:https://blog.csdn.net/sinat_27612147/article/details/80798452 写在前面 预加载方案 ...

最新文章

  1. 单机/伪分布式Hadoop2.4.1安装文档
  2. 一张图搞清楚Java异常机制
  3. composer查看当前镜像取消_国内全量镜像大全
  4. 关于软件测试学习心得
  5. UC浏览器电脑版怎么设置字体大小 UC浏览器字体设置教程
  6. 【AI视野·今日CV 计算机视觉论文速览 第238期】Fri, 1 Oct 2021
  7. cupload怎么保存图片_图片标注软件labelImg使用指南
  8. Go语言开发(九)、Go语言并发编程
  9. 在 Ubuntu 18.04 上安装 Python 3.7
  10. 拓端tecdat|R语言ARMA-EGARCH模型、集成预测算法对SPX实际波动率进行预测
  11. Linu下建立svn版本库
  12. 品优购06——运营商后台(商品管理)
  13. 00001__伊丽莎白福尔摩斯
  14. SYN报文什么时候会被丢弃?
  15. 在国企的 Java 程序员是一种什么样的体验?让我来告诉你吧!
  16. 【日常分享】多邻国v4.93.4,在线学习英语、日语、韩语、德语…等30多种语言
  17. python中的%用法
  18. 数字集成电路设计系列学习总结
  19. EDA开源仿真工具verilator入门9:资料总结和最新版本安装
  20. superslide问题汇总

热门文章

  1. bigfile.to服务器位置,Cloudera Manager 迁移服务器
  2. 【BIM入门实战】Revit 图元分类有哪三种?Revit图元分类图文详解
  3. C#正则表达式判断输入的是不是数字
  4. C语言试题十二之m个人的成绩存放在score数组中,请编写函数function,它的功能是:将低于平均分的人数作为函数值返回,将低于平均分的分数放在below所指定的数组中。
  5. Android之属性动画初步
  6. 一维数组和二维数组的区别_数组指针和指针数组的区别
  7. mysql 5.7 主从切换_mysql5.7 主从复制的正常切换【转】
  8. 当代成年人的生活状态......
  9. 并不是每个女生都能穿出这种效果......
  10. 没有女朋友,可能是因为你数学不好