web前端 网页加载 性能优化大全
web前端 性能优化 — — 如何提高网页加载速度
文章目录
- web前端 性能优化 --- --- 如何提高网页加载速度
- 1. 减少DNS查找
- 2. 使用CDN托管资源
- 3. 减少Http请求
- 浏览器发送Http请求过程[^2]
- 4. 压缩文本和图像`Gzip`
- Treeshaking、Scope hoisting、Code splitting
- 5. 善用缓存`添加Expires头,配置Etag...`
- 浏览器缓存
- `Expires`:
- `Cache-control`:
- `Last-Modified & if-modified-since`:
- `ETag & If-None-Match`:
- 本地缓存
- 6.使用Ajax来增强进程
- 7. CSS优先加载,JS延迟加载
- CSS加载优化
- JS加载优化(异步加载)
- 8. 延迟渲染Below the fold内容(懒加载)
- *懒加载*
- 9. 使用HTML5和CSS 3.0来简化页面
- 10.一些编写代码的优化
- 11. 将Click事件替换成Touch事件
- 12. 减少重定向
- 13. 首次使用的时候在HTML中嵌入资源
- 14. 代码精简和混淆
- 15. 使用HTML5服务端发送事件
- 16. 对多线程来说尽量使用HTML5的Web Worker特性
- 17. 根据网络状况进行适配处理
- *使用JS在浏览器中判断当前网络连接状态的几种方法*
1. 减少DNS查找
DNS(Domain Name System)
: 负责将域名URL转化为服务器主机IP。:把域名转换成为网络可以识别的ip地址
DNS查找流程:首先查看浏览器缓存是否存在,不存在则访问本机DNS缓存,再不存在则访问本地DNS服务器。所以DNS也是开销,通常浏览器查找一个给定URL的IP地址要花费20-120ms,在DNS查找完成前,浏览器不能从host那里下载任何东西。
TTL(Time To Live):表示查找返回的DNS记录包含的一个存活时间,过期则这个DNS记录将被抛弃
DNS优化两个方面:DNS缓存、DNS负载均衡
影响DNS缓存的因素
- 服务器可以设置TTL值表示DNS记录的存活时间。本机DNS缓存将根据这个TTL值判断DNS记录什么时候被抛弃,这个TTL值一般都不会设置很大,主要是考虑到快速故障转移的问题
- 浏览器DNS缓存也有自己的过期时间,这个时间是独立于本机DNS缓存的,相对也比较短,例如chrome只有1分钟左右
- 浏览器DNS记录的数量也有限制,如果短时间内访问了大量不同域名的网站,则较早的DNS记录将被抛弃,必须重新查找。不过即使浏览器丢弃了DNS记录,操作系统的DNS缓存也有很大机率保留着该记录,这样可以避免通过网络查询而带来的延迟。
最佳实践
当客户端的DNS缓存为空时,DNS查找的数量与Web页面中唯一主机名的数量相等。所以减少唯一主机名的数量就可以减少DNS查找的数量。
然而减少唯一主机名的数量会潜在地减少页面中并行下载的数量,避免DNS查找降低了响应时间,但减少并行下载可能会增加响应时间。当页面的组件量比较多的时候,可以考虑将组件分别放到至少2-4个主机名,已获得最大收益
2. 使用CDN托管资源
CDN (Content Delivery Network)
可直译成内容分发网络。CDN的本质仍然利用缓存技术缓存, 解决的是如何将数据快速可靠从源站传递到用户的问题。用户获取数据时,不需要直接从源站获取,通过CDN对于数据的分发,用户可以从一个较优的服务器获取数据,从而达到快速访问,并减少源站负载压力的目的
即 — 把资源放在离用户地理位置更近的地方
用户在通过浏览器访问未使用CDN加速的网站的大致过程:
- 用户在浏览器中输入要访问的域名。
- 浏览器向DNS服务器请求对该域名的解析。
- DNS服务器返回该域名的IP地址给浏览器。
- 浏览器使用该IP地址向服务器请求内容。
- 服务器将用户请求的内容返回给浏览器。
CDN访问过程
- 用户向浏览器提供要访问的域名
- 浏览器调用域名解析库对域名进行解析,由于CDN对域名解析过程进行了调整,所以解析函数库一般得到的是该域名对应的CNAME记录,为了得到实际IP地址,浏览器需要再次对获得的CNAME域名进行解析以得到实际的IP地址。在此过程中,使用的全局负载均衡DNS解析,如根据地理位置信息解析对应的IP地址,使得用户能就近访问;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器的负载情况,判断哪一台服务器的负载较小
- 此次解析得到CDN缓存服务器的IP地址,浏览器在得到实际的IP地址以后,向缓存服务器发出访问请求
- 缓存服务器根据浏览器提供的要访问的域名,通过Cache内部专用DNS解析得到此域名的实际IP地址,再由缓存服务器向此实际IP地址提交访问请求
- 缓存服务器从实际IP地址得得到内容以后,一方面在本地进行保存,以备以后使用,二方面把获取的数据返回给客户端,完成数据服务过程
- 客户端得到由缓存服务器返回的数据以后显示出来并完成整个浏览的数据请求过程
使用CDN可以解决资源并行下载限制,处理静态资源Cookie同域名携带等问题;
CDN缓存和回源需要合理的设置静态资源hash;
接入CDN会引入多个域名,增加域名解析时间,可进行预解析域名
<link rel="dns-prefetch" href="//js.dns.com" />
使用CDN服务的网站,只需将其域名的解析权交给CDN的负载均衡设备,CDN负载均衡设备将为用户选择一台合适的缓存服务器,用户通过访问这台缓存服务器来获取自己所需的数据。
由于缓存服务器部署在网络运营商的机房,而这些运营商又是用户的网络服务提供商,因此用户可以以最短的路径,最快的速度对网站进行访问。因此,CDN可以加速用户访问速度,减少源站中心负载压力。
3. 减少Http请求
浏览器发送Http请求过程1
- DNS 查找 IP 地址 :
DNS查找:浏览器缓存 -> 系统缓存 -> 路由器缓存 -> ISP DNS缓存 -> 递归搜索
DNS域名解析 - 三次握手建立 TCP 连接
- 服务器的永久重定向响应:返回真正访问的地址;
- 浏览器跟踪重定向地址:另发一个 http 请求;
- 服务器接收到获取请求,然后处理并返回一个http响应,浏览器得到html代码。
- 浏览器解析 html 页面:解析 html 以构建 DOM 树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树
- 浏览器请求html代码中的资源,获取嵌入在 html 中的资源(如图片、音频、视频、CSS 、JS 等等);
- 浏览器对页面进行渲染呈现给用户
- 服务器关闭关闭TCP连接(四次挥手终止连接)
- DNS 查找 IP 地址 :
一个http请求绝大多数的时间消耗在了建立连接跟等待的时间,优化的方法是减少http请求。
- 减少图片的请求:css sprites、内联图片、IconFont。
- 减少脚本与样式表的请求主要原则就是合并:将多个样式表或者脚本文件合并到一个文件中,可以减少HTTP请求的数量从而缩短效应时间。
- 然而合并所有文件对许多人尤其是编写模块化代码的人来说是不能忍的,而且合并所有的样式文件或者脚本文件可能会导致在一个页面加载时加载了多于自己所需要的样式或者脚本,对于只访问该网站一个(或几个)页面的人来说反而增加了下载量,所以大家应该自己权衡利弊。
4. 压缩文本和图像Gzip
前端生产环境中将js、css、图片等文件进行压缩的好处显而易见,通过减少数据传输量减小传输时间,节省服务器网络带宽,加快加载文本的速度,提高前端性能
而且测试表明,压缩对网站还是起到优化性能的作用的,那些基于文本的响应,包括HTML,XML,JSON(Javascript Object Notation),Javascript,和CSS可以减少大约70%的大小。
目前比较通用的压缩方法是启用gzip压缩
。它会把浏览器请求的页面,以及页面中引用的静态资源以压缩包的形式发送到客户端,然后在客户端完成解压和拼装.
http协议对压缩文件的传输的支持
浏览器请求数据时,通过Accept-Encoding申明自己可以接受的压缩方法
服务端接收到请求后,选取Accept-Encoding中的一种对响应数据进行压缩
服务端返回响应数据时,在Content-Encoding字段中说明数据的压缩方式
浏览器接收到响应数据后根据Content-Encoding的响应头对结果进行解压
注:如果服务器没有对响应数据进行压缩,则不返回Content-Encoding,浏览器也不进行解压
- 压缩的时间
时间 | 流程 | 说明 |
---|---|---|
服务端响应请求时 | 服务端接收请求后找到响应文件,并进行压缩,然后将压缩后的文件作为内容返回给客户端 | 压缩等级越高压缩效果越好,同时CPU消耗也越大,压缩时间也越长。为了减少响应时间这一目的,服务端响应请求时压缩等级不宜过高 |
构建时 | 项目构建时将文件压缩后发布 | 构建时压缩不占用响应时间,可以选择较高的压缩等级,生成压缩后的文件后部署到服务器 |
结合使用 | 请求根据文件类型,大小,请求频率等对压缩时间做策略选择 | 构建时对需要压缩的文件进行压缩;服务器在收到请求后首先查找对应的已压缩文件,找不到的情况下使用服务端压缩 |
- 服务器响应请求时压缩
nginx
- 构建时压缩
webpack
使用插件:cnpm install --save-dev compression-webpack-plugin
webpack
配置
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
plugins:[new CompressionWebpackPlugin({ //这里对大于10k的js和css文件进行压缩,其它配置参考官方文档filename: '[path].gz[query]', // 目标资源名称 [file]会被替换成原资源,[path]替换成原资源路径 [query]替换成原查询字符串algorithm: 'gzip' // 算法test: /\.(js|css)$/, // 压缩js与cssthreshold: 10240, // 只处理比这个值大的资源,按字节计算minRatio: 0.8 // 只有压缩率比这个值小的资源才会被处理})
]
后台开启使用koa
const staticCache = require('koa-static-cache')
import config from './config'
const app = new Koa()
app.use(staticCache(path.resolve(_dirname, "../dist"), {maxAge: 7 * 24 * 60 * 60,gzip: true, // 开启dynamic: true
}))
Treeshaking、Scope hoisting、Code splitting
Tree shaking
—— 清除不使用的代码,找出使用的代码Scope hoisting
——检查import链,并尽可能的将散乱的模块放到一个函数中,前提是不能造成代码冗余,所以只有被引用了一次的模块才会被合并Code-splitting
—— 能够把代码分离到不同的bundle中,然后可以按需加载或并行加载这些文件。
基于 ES6 的静态引用,
Tree shaking
通过扫描所有 ES6 的 export,找出被 import 的内容并添加到最终代码中。 webpack 的实现是把所有 import 标记为有使用/无使用两种,在后续压缩时进行区别处理
使用Scope Hoisting
可以让代码体积更小并且可以降低代码在运行时的内存开销,同时它的运行速度更快。Scope Hoisting可以减少搜索时间。(变量从局部作用域到全局作用域的搜索过程越长执行速度越慢)
Code-splitting
可以用于获取更小的bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
- 生产环境
proxy_pass + gzip
5. 善用缓存添加Expires头,配置Etag...
- 缓存:CDN缓存,DNS缓存,浏览器缓存,本地缓存,Service Worker…
浏览器缓存
自动化缓存-处理大规模缓存:
http-Header(协议头部):基于http-Request(请求头部)和http-Response(响应头)来实现的缓存策略
对http请求来说,客户端缓存分三类:
- 不发任何请求,直接从缓存中取数据(本地缓存)如:
Expires
,Cache-Control=<number!=0>
和appcache
- 发请求确认是否新鲜,再决定是否返回304并从缓存中取数据(协商缓存)如:
Last-Modified/If-Modified-Since
,Etag/If-None-Match
- 直接发送请求, 没有缓存,如:
Cache-Control:max-age=0/no-cache
- 不发任何请求,直接从缓存中取数据(本地缓存)如:
现在所有的浏览器都会使用本地资源去缓存住那些被Cache一Control或者Expires头标记的资源,这些头能标记资源需要缓存的时间。
另外,ETag(实体标签)和Last一Modified头来标识当资源过期后是否需要重新请求,浏览器为了减少不必要的服务器请求,尽可能地从本地缓存中获取资源,并且将那些已经过期的、或者当缓存空间减小的时候将那些很久不用的资源进行清理。
浏览器缓存通常包括图片,CSS,Javascript代码,这些缓存能合理地提高网站的性能(比如为了支持后退和前进的按钮,使用一个单独的缓存来保存整个渲染的页面)
Expires
:
指定缓存到期GMT的绝对时间,指服务端具体时间点,过期之前均从浏览器缓存读取数据。如果设了max-age,max-age就会覆盖expires。如果expires到期需要重新请求。
Cache-control
:
假设你的站点有引用一个脚本文件,你非常确认这个脚本文件内容十年不变。那么自然希望浏览器把这个脚本缓存起来,不用每一次都请求服务器,然后服务器再返回相同的内容。这样能够节省带宽开销并且提升性能。
设置文件返回的HTTP头中的Cache-Control设置为:Cache-Control: max-age=31536000
(标准中规定max-age值最大不能超过一年,以秒为单位,值为31536000)
Cache-Control:
public
:表示缓存的版本可以被代理服务器或者其他中间服务器识别。
private
:意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
no-cache
:意味着文件的内容不应当被缓存。这在搜索或者翻页结果中非常有用,因为同样的URL,对应的内容会发生变化。
相关字段:
max-age
:指定缓存的有效时间(以秒为单位),max-ag=0或者是负值,浏览器会在对应的缓存中把Expires设置为1970-01-01 08:00:00。
s-maxage
:类似于max-age,只能指定Public类型的共享缓存,优先级高于max-age,比如proxy。
private
:私有缓存,如果个人计算机上的缓存
public
:公开缓存,如cdn服务器上的资源缓存,因为共很多用户使用所以是public。通常情况下需要http身份验证的情况,响应是不可cache的,加上public可以使它被cache。
no-cache
: 强制浏览器在使用cache拷贝之前先提交一个http请求到源服务器进行确认。请求获取当前服务器端该文件的Last-Modified对比判断是否使用继续使用本地缓存文件
no-store
:告诉浏览器在任何情况下都不要进行cache,不在本地保留拷贝。
must-revalidate
: 强制浏览器严格遵守你设置的cache规则。
proxy-revalidate
: 强制proxy严格遵守你设置的cache规则。
cache
:使用本地缓存,不发生请求。
Last-Modified & if-modified-since
:
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
ETag & If-None-Match
:
Etag(全称Entity Tag.):web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定,具体下文中介绍)。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。
Etag和304类似,但是级别比 Last-Modified 高一些
- 304:通过If-Modified-Since If-Match判断资源是否修改,如未修改则返回304,发生了一次请求,但请求内容长度为0,节省了带宽。 如果有多台负载均衡的服务器,不同服务器计算出的Etag可能不同,这样就会造成资源的重复加载。
过程:
- 客户端请求一个页面(A)。
- 服务器返回页面A,并在给A加上一个Last-Modified/ETag。
- 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
- 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。
- 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体
Etag 主要为了解决 Last-Modified 无法解决的一些问题:
某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存,这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是秒级的,它将不能准确标注文件的修改时间。(或者说UNIX记录MTIME只能精确到秒);
某些服务器不能精确的得到文件的最后修改时间,或者与代理服务器时间不一致等情形
本地缓存
- Cookie、localStorage、以及sessionStorage之间的区别2
缓存 | cookie | localStorage | sessionStorage |
---|---|---|---|
大小数量 | 不能超过4K | 5M或更大 | 5M或更大 |
有效性 | 可以设置path路径,限制只属于某个路径。在设置的过期时间之前一直有效,即使窗口或浏览器关闭 | 始终有效,存储持久数据,浏览器关闭后数据不丢失,除非主动删除数据 | 数据在当前浏览器窗口关闭后自动删除(会话级) |
操作方法 | 修改读取方法需自己实现 | 提供了get,set方法 | 提供了get,set方法 |
作用域 | 所有同源窗口中都共享 | 所有同源窗口中都共享 | 不在不同的浏览器窗口中共享,即使是同一个页面 |
数据与服务器之间的交互方式 | 每次请求都会自动发送到服务器,然后回传给浏览器,服务器端也可以写cookie到客户端 | 不会自动把数据发给服务器,仅在本地保存 | 不会自动把数据发给服务器,仅在本地保存 |
Web Storage带来的好处:
1、减少网络流量:一旦数据保存在本地之后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要的来回传递
2、快速显示数据:性能好,从本地读数据比通过网络从服务器上获得数据快得多,本地数据可以及时获得,再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示
3、临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便
补:web Storage支持事件通知机制,可以将数据更新的通知发送给监听者
web Storage的api接口使用更方便
6.使用Ajax来增强进程
待更新ing
7. CSS优先加载,JS延迟加载
- 将CSS文件放在顶部,JS文件放在底部
CSS加载优化
- 将首屏页面要用到的关键CSS文件,内联到HTML文档中;
- 异步加载CSS:loadCSS 和 Preload
- 使用JavaScript动态创建样式表link元素,并插入到DOM中。
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
将link元素的media属性设置为用户浏览器不匹配的媒体类型(或媒体查询),如media=“print”,甚至可以是完全不存在的类型media=“noexist”。对浏览器来说,如果样式表不适用于当前媒体类型,其优先级会被放低,会在不阻塞页面渲染的情况下再进行下载。文件加载完成之后,将media的值设为screen或all,从而让浏览器开始解析CSS。
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。加载完成之后,将rel改回去。
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
可以使用 loadCSS和 Preload
- 考虑兼容问题,可以使用 loadCSS
- Preload:
// 对于一些不是首屏加载的css,可以如下写法:
<link rel="preload" href="path/to/haorooms.css" as="style" onload="this.rel='stylesheet'">// 防止浏览器禁止js,保险起见,也可以如下:
<link rel="preload" href="path/to/haorooms.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="path/to/haorooms.css"></noscript>// 为了避免有些浏览器会重新调用处理程序rel='stylesheet'这个属性,我们一般推荐如下写法:
<link rel="preload" href="path/to/haorooms.css" as="style" onload="this.οnlοad=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="path/to/haorooms.css"></noscript>// 不考虑兼容问题再次优化
<head><link rel="stylesheet" href="/首屏加载css.css"><link rel="preload" href="/不是首屏加载的css.css" as="style" onload="this.οnlοad=null;this.rel='stylesheet'">
</head>
<body><header>…</header><main>…</main><section class="comments">…</section><section class="about-me">…</section><footer>…</footer>
</body>
- CSS使用技巧
有选择的使用选择器
保持简单,不要使用嵌套过多过于复杂的选择器。
通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
不要使用类选择器和ID选择器修饰元素标签,如h3#markdown-content,这样多此一举,还会降低效率。
不要为了追求速度而放弃可读性与可维护性。减少使用昂贵的属性
如box-shadow/border-radius/filter/透明度/:nth-child等。减少重排,避免不必要的重绘
不使用CSS @import —— CSS的@import会造成额外的请求
避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
JS加载优化(异步加载)
- defer属性
通过给<script>
标签设置defer属性,将脚本文件设置为延迟加载,当浏览器遇到带有defer属性的<script>
标签时,会再开启一个线程去下载js文件,同时继续解析HTML文档,等等HTML全部解析完毕DOM加载完成之后,再去执行加载好的js文件
只适用于引用外部js文件的<script>
标签,可以保证多个js文件的执行顺序就是它们在页面中出现的顺序,但是要注意,添加defer属性的js文件不应该使用document.write方法 - async属性
async属性和defer属性类似,也是会开启一个线程去下载js文件,但和defer不同的时,它会在下载完成后立刻执行,而不是会等到DOM加载完成之后再执行,所以还是有可能会造成阻塞。
async也是只适用于外部js文件,也不能在js中使用document.write
方法,但是对多个带有async的js文件,它不能像defer那样保证按顺序执行,它是哪个js文件先下载完就先执行哪个。 - 动态创建
<script>
标签
通过动态地创建<script>
标签来实现异步加载js文件
8. 延迟渲染Below the fold内容(懒加载)
如果将不可见区域的内容延迟加载,那么页面就会更快地展现在用户面前,这个区域叫做below the fold
,为了减少页面加载后需要重新访问的内容,可以将图片替换为正确的高宽所标记的<img>
标签
- 通过Intersection Observer延迟加载图片、视频、广告脚本、或任何其他资源。
- 先加载低质量或模糊的图片,当图片加载完毕后再使用完整版图片替换它。
- 延迟加载所有体积较大的组件、字体、JS、视频或Iframe。
懒加载
实现原理
- 页面中img元素,如果没有src属性,浏览器就不会发出请求去下载图片,只有通过js设置图片路径,浏览器才会发送请求;
- 懒加载的原理是先在页面中把所有的图片统一使用一张占位图进行占位,把真正的路径存在元素的‘data-url’属性中,要使用的时候,在设置。
实现
- 首先,不要将图片地址放到src属性中,而是放到其它属性(data-original)中。
- 页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中。
- 在滚动事件中重复判断图片是否进入视野,如果进入,则将data-original属性中的值取出存放到src属性中。
9. 使用HTML5和CSS 3.0来简化页面
HTML5包括了一些新的结构元素,例如header,nav,article和footer,使用这些 语义化标签 比传统的使用div和span标签能使得页面更简单和更容易解析。
HTML5的一些表单元素提供了许多新属性来完成原本需要javascript来完成的功能,placeholder,autofocus等;也有一些新的输入框元素能不用依靠Javascript就可以完成一些通用的需求,包括像e-mail,url,tel,time等。
使用CSS 3.0中的圆角,阴影,动画,过渡和其他的图片效果,轻便简易,加速渲染
10.一些编写代码的优化
- 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
- 当需要设置的样式很多时设置className而不是直接操作style。
- 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
- 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢。
- 善于使用事件委托
- 用Map代替大量的if…else和switch会提升性能
- 防抖与节流
- 避免使用空的src和href
- a标签设置空的href,会重定向到当前的页面地址
- form设置空的method,会提交表单到当前的页面地址
- 图片优化
- Base64 —— 将图片的内容以Base64格式内嵌到HTML中,可以减少HTTP请求数量。但是,由于Base64编码用8位字符表示信息中的6个位,所以编码后大小大约比原始值扩大了 33%
- 使用字体图标来代替图片
- 图片大小控制合适
- 尽可能通过srcset,sizes和元素使用响应式图片(可以在不同屏幕尺寸与分辨率的设备上自动切换图片大小、自动裁切图片等)
- 减少像素点/减少每个相似度能够显示的颜色
11. 将Click事件替换成Touch事件
在触摸屏设备上,当一个用户触碰屏幕的时候,
onclick
事件并没有立即触发,设备会使用大约半秒(大多数设备差不多都是300毫秒)来让用户确定是手势操作还是点击操作,这个延迟会很明显地影响用户期望的响应性能,要使用touchend
事件来替换才能解决,当用户触碰屏幕的时候,这个事件会立即触发。
为了要确保不会产生用户不期望的行为,应该使用touchstart
和touchmove
事件。也可以在touchstart
事件之后使用touchmove
事件来避免将touchend
事件误判为点击,当然前提是需要假设拖拽的手势并不是预期产生点击行为。
我们需要去处理onclick
事件来让浏览器改变button
的外观从而标识为已点击的状态,同时也需要处理那些不支持touch
事件的浏览器,为了避免代码在touchend
和onclick
代码中重复执行,需要在确保用户触碰事件已经在touchend
执行了之后,在click事件中调用preventDefault
和stopPropagation
方法。
12. 减少重定向
重定向用于将用户从一个URL重新路由到另一个URL。
重定向会增加http请求的次数,会影响到整个网站的性能,但是必要的重定向又可以提高用户体验,所以我们需要在性能和用户体验之间去权衡
- 常用重定向类型
- 301:永久重定向,主要用于当网站的域名发生变更之后,告诉搜索引擎域名已经变更了,应该把旧域名的的数据和链接数转移到新域名下,从而不会让网站的排名因域名变更而受到影响。
- 302:临时重定向,主要实现post请求后告知浏览器转移到新的URL。
- 304:Not Modified,主要用于当浏览器在其缓存中保留了组件的一个副本,同时组件已经过期了,这是浏览器就会生成一个条件GET请求,如果服务器的组件并没有修改过,则会返回304状态码,同时不携带主体,告知浏览器可以重用这个副本,减少响应大小。
如何避免重定向
- 在定义链接地址的href属性的时候,尽量使用最完整的、直接的地址(不要缺失结尾的/ )
- 在使用Response.Redirect的时候,设置第二个参数为false
考虑是否可用Server.Execute代替
考虑Respone.RedirectPermanent - 如果涉及到从测试环境到生产环境的迁移,建议通过DNS中的CNAME的机制来定义别名,而不是强制地重定向来实现
13. 首次使用的时候在HTML中嵌入资源
从性能的角度来说,如果一个资源没有很高的被缓存的几率的话,最好把它嵌入到页面的HTML中(叫inlining),而不是使用链接外部,脚本和样式是支持内嵌到HTML中的,但是图片和其他的二进制资源其实也是可以通过内嵌包含base64编码的文本来嵌入到HTML中的。
内嵌的缺点是页面的大小会变得非常大,所以对于Web应用来说,关键的是能够跟踪分析这个资源什么时候需要从服务端获取,什么时候已经缓存到客户端了。
14. 代码精简和混淆
- 精简:目的是减少代码体积,减小网络传输时间,提高页面响应。
1.删除代码注释
2.删除无意义或者多余的空白(如空格,制表符,回车,换行)
3.删除可以省略的符号
4.缩短语句(如css的简写,html中disabled=‘disabled’ 改成disabled , js中缩短局部变量)
Tools: yuicompresser, closure complie, jsmin, packer…
混淆:主要针对Javascript代码,它的目的是减低代码的可读性,防止被追踪出程序逻辑。会从javascript代码中移除注释和空白,另外也会改写代码。作为改写的一部分,函数和变量的名字将被转换为更短的字符串,所以进一步减少了javascript文件的大小。(混淆更能减少js代码的大小)。
- 缺陷:混淆过程本身很有可能引入错误。
- 维护:由于混淆会改变javascript符号,因此需要对任何不能改变的符号进行标记,防止混淆器修改它们。
- 调试:经过混淆的代码很难阅读,这使得在产品环境中更加难以调试。
压缩
编译
15. 使用HTML5服务端发送事件
HTML5的EventSource对象和Server-Sent事件能通过浏览器端的JavaScript代码打开一个服务端连接客户端的单向通道,服务端可以使用这个写通道来发送数据,这样能节省了HTTP创建多个轮询请求的消耗。
这种方式比HTML的WebSocket更高效,WebSocket的使用场景是,当有许多客户端和服务端的交互的时候(比如消息或者游戏),在全双工连接上建立一个双向通道。
- 需要基于具体的技术实现的,如果你的网站当前是使用其他的Ajax或者Comet技术来轮询的,转变成Server-Sent事件需要重构网站的Javascript代码。
16. 对多线程来说尽量使用HTML5的Web Worker特性
HTML5中的Web Worker是使用多个线程并发执行Javascript程序
Web Worker 使用教程
- Web Worker中的代码很适合用来预处理用户完成进一步操作所需要的资源的,特别是在用户的带宽资源不紧缺的情况下,在低处理器性能的移动设备上,过多的预加载可能会干扰当前页面的UI响应,使用多线程代码,让Web Worker对象(并且尽可能使用localStorage来缓存数据)在另外一个线程中操作预加载资源,这样就能不影响当前的UI表现了
- Web Worker只在Android 2.0以上的版本实现,而且iphone上的ios5之前的版本也不支持,在桌面PC上,总是落后的IE只在IE 10才支持Web Worker。
- Web Workers不能进入到页面的DOM,也不能改变页面上的任何东西,Web Worker很适合那种需要后台计算和处理的工作。
17. 根据网络状况进行适配处理
由于使用更多带宽会使用更多移动网络的费用,所以只有能检测网络的类型才能使用针对特定网络的优化技术。
例如,预加载未来使用到的请求是非常聪明的做法,但是如果用户的带宽很稀有,并且加载的有些资源是永远不会用到的话,则duck不必。
使用JS在浏览器中判断当前网络连接状态的几种方法
- navigator.onLine
通过navigator.onLine判断当前网络状态:
if(navigator.onLine){...
}else{...
}
非常简单,但是并不准确——根据MDN的描述:
navigator.onLine只会在机器未连接到局域网或路由器时返回false,其他情况下均返回true。
也就是说,机器连接上路由器后,即使这个路由器没联通网络,navigator.onLine仍然返回true。
- ajax请求
采用get请求的方式,根据返回值判断是否能够成功get到数据,从而确定当前的网络状态:
$.ajax({url: 'x.html',success: function(result){...}, error: function(result){...}
});
- 获取网络资源
原理同2,在页面放一张隐藏图片,设置其onerror函数(获取图片资源失败时会调用该函数):
<script src="./jquery-3.1.1.min.js"></script>
<script>
function getImgError(){alert("Network disconnect!");
}
$().ready(function(){$("#btn-test").click(function(){var imgPath = "https://www.baidu.com/img/bd_logo1.png";var timeStamp = Date.parse(new Date());$("#img-test").attr("src", imgPath + "?timestamp=" + timeStamp);});
});
</script>
<body><img id="img-test" style="display:none;" onerror="getImgError()"/><button id="btn-test">check status</button>
</body>
每次点击button时,更新该图片的src。若获取图片失败,则认为网络连接失败
这种判断网络状态的准确完全取决于图片资源是否稳定
- bind()
原理同1:
var netStatue = true;
$(window).bind('online', function(){netStatue = true;
});
$(window).bind('offline', function(){netStatue = false;
});
...
if(netStatue){...
}else{...
}
*浏览器发送Http请求过程 ↩︎
*Cookie、localStorage、以及sessionStorage之间的区别 ↩︎
web前端 网页加载 性能优化大全相关推荐
- H5缓存机制浅析-移动端Web加载性能优化【干货】
转载:H5缓存机制浅析-移动端Web加载性能优化[干货] 作者:贺辉超,腾讯游戏平台与社区产品部 高级工程师 目录 1 H5缓存机制介绍 2 H5缓存机制原理分析 2.1 浏览器缓存机制 2.2 Do ...
- 分享网页加载速度优化的一些技巧?
日期:2013-2-17 来源:GBin1.com 不管你是不是相信,在最近的几年里,互联网网页的大小已经显著增大了.由HTTP Archive研究得出的结果表明,目前平均一个页面的大小是1.25M ...
- 关于图片加载性能优化总结
Android 图片加载性能优化总结 一.Android Bitmap加载大尺寸图片优化: 压缩原因: 1.imageview大小如果是200*300那么加载个2000*3000的图片到内存中显然是 ...
- 清除浏览器缓存之后为什么还是显示旧的html页面_H5缓存机制浅析-移动端Web加载性能优化...
1 H5缓存机制介绍 H5,即HTML5,是新一代的HTML标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5引入的离线存储,这意味着 web 应用可进行缓存,并可在没 ...
- H5缓存机制浅析-移动端Web加载性能优化
1 H5缓存机制介绍 H5,即HTML5,是新一代的HTML标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5引入的离线存储,这意味着 web 应用可进行缓存,并可在没 ...
- 如何提升网页加载性能
摘自 https://github.com/xitu/gold-miner/blob/master/TODO/building-a-shop-with-sub-second-page-loads-le ...
- React 16 加载性能优化指南
关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...
- html标签 资源加载失败,前端资源加载失败优化
Web 项目上线后,开始开门迎客,等待着来自大江南北.有着各式各样网络状态的用户莅临.在千差万别的网络状态中,访问页面难免会遇到前端资源加载失败的情况,占比或许不高,但一遇到,轻则页面样式错乱,重则白 ...
- nuxt解决首屏加载慢问题_滴普大前端 | 滴普是如何实现首屏加载性能优化的?...
决定优化方向 首先打开 Inspect - Network 查看请求情况,从图片可以看出,DOMContentLoaded 时间为 2.67s,Load 时间为 3.45s,资源交换为 2.4MB. ...
最新文章
- Keycloak Spring Security适配器的常用配置
- 适合vue的富文本框
- 转 多租户SaaS架构
- 表的基本查询(数据库篇)
- 设计模式----java的单例模式
- 利用LDA主题模型的生成过程仿真数据
- java后端做教育视频网站源码_【Java并发面试点】看这一篇应该是够了
- 2021显著目标检测(SOD)方向部分论文汇总
- 书柜的尺寸(bzoj 1933)
- mysql中文占两位_mysql 保留两位小数
- x200装linux驱动下载,佳能 ThinkPad X200 Tablet 驱动程序下载-更新佳能软件(平板电脑)...
- 分析LOIC流,判断DDoS攻击源
- 米思齐(Mixly)图形化系列教程(四)-运算符
- Photoshop CS6安装教程
- Python实现太极图案
- 由课堂思考生活(作者:张子逸)
- 使用docker官方加速器
- springboot Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory
- 第 5-5 课: 如何打包部署 Spring Boot 项⽬
- 纯干货讲解财务三大报表,值得收藏