写点什么

浅析 Web 前端性能优化

  • 2020-02-14
  • 本文字数:2699 字

    阅读完需:约 9 分钟

浅析Web前端性能优化

什么是 WEB 前端呢?就是用户电脑的浏览器,所做的一切事情。我们来看看用户访问网站,浏览器都做了哪些事情。


输入网址 –> 解析域名 -> 请求页面 -> 解析页面并发送页面中的资源请求 -> 渲染资源 -> 输出页面 -> 监听用户操作 -> 重新渲染。


通过上面可以看出浏览器分为三部分来实现用户的使用,我们就从这三个部分来浅析如何提升 WEB 前端性能。


一、 请求


浏览器为了减少请求传输,实现了自己的缓存机制。浏览器缓存就是把一个已经请求过的 Web 资源拷贝一份副本存储在浏览器中。当再次请求相同的 URL 时,先去查看缓存,如果有本地缓存,浏览器缓存机制会根据验证机制(Etag)和过期机制(Last-Modified)进行判断是使用缓存,还是从服务器传输资源文件。具体流程如下图所示:


1506321631051056382.png


浏览器的请求有些是并发的,有些是阻塞的。图片、CSS、接口的请求是并发,JS 文件是阻塞的。请求 JS 的时候,浏览器会中断渲染进程,等待 JS 文件加载解析完毕,再重新渲染。所以要把 JS 文件放在页面的最后。


JS 也可以通过两种方式由阻塞改成并行。一种是通过创建 script 标签,插入 DOM 中;另一种是在 Script 标签中增加 async 属性。


每种浏览器对同一域名并发的数量有限制,IE6/7 是 2,IE9 是 10,其他常见的浏览器是 6,所以减少资源请求数量和使用多域名配置资源文件,能大大提高网站性能。


减少资源请求数量的方法,大致有以下几种:


1、 通过打包工具,合并资源,减少资源数量。就是开发版本是很多个资源文件,部署的时候,按类合并成几个文件来输出。在实现模块管理的同时,实现统一输出。


2、 CSS 中,使用 css sprite 减少图片请求数量。


3、 通过延迟加载技术,在用户无感知的情况下请求资源。


4、 通过服务器配置,实现一次请求,返回多个资源文件,如淘宝 CDN 那样。


除了减少请求数量,也可以使用 CDN 镜像,来减少网络节点,实现快速响应。使用了 CDN 的请求,会根据用户所处的地理位置,找寻最近的 CDN 节点,如果请求是新的,则从资源服务器拷贝到节点,然后再返回给客户端。如果请求已经存在,则直接从节点返回客户端。


通过上面我们了解的缓存机制,如果我们部署上线的时候,是需要刷新缓存的。普通缓存通过强刷就能改过来,而 CDN 缓存则需要通过改变 URL 来实现。同时我们不可能要求用户按着 Ctrl 来刷新,所以通过打包工具,在部署的时候,统一更改 URL 是最有效的方式。而不常变更的库文件,比如 echart、jquery,则不建议更改。


二、 传输


从服务器往客户端传输,可以开启 gzip 压缩来提高传输效


Gzip 有从 1-10 的十个等级。越高压缩的越小,但压缩使用的服务器硬件资源就越多。根据实践,等级为 5 的时候最均衡,此时压缩效果是 100k 可以压缩成 20k。


三、 渲染


浏览器在加载了 html 后,就会一边解析,一边根据解析出来


结果进行资源请求,并生成 DOM 树。而加载完毕的 CSS,则被渲染引擎根据生成好的 DOM 树,来生成渲染树。等所有资源解析完毕计算好 layout 后,向浏览器界面绘制。随着用户操作,JS 会修改 DOM 节点或样式,重新绘制和重新排列。重新绘制指的是绘制 DOM 节点对应的渲染节点,重新排列是指重新计算这些节点在浏览器界面的位置。很显然,重排是非常耗性能的。我们要做的是减少重排的次数。


生成 DOM 树的时候,我们可以通过减少 DOM 节点来优化性能。最初都是用 table 布局,节点深度和数量相当复杂,性能很差。同样 CSS 作为层叠样式表,层级也不可太深,不然遍历的成本很高。另外 CSS 的 expression 属性相当耗性能,能不用则不用。动画效果能用 CSS 写的就不用 JS 写,渲染引擎不一样,性能损耗也不一样。


上面说的是解析渲染的过程,我们再接着说说用户交互操作的过程。用户操作就会导致重绘和重排,重排一定会引起重绘,而重绘不一定会引起重排。到底怎样会引起重排呢?简单的定义,DOM 结构的变化,以及 DOM 样式中几何属性的变化,就会导致重排。几何属性顾名思义,就是宽、高、边框、外补丁、内补丁等俗称盒模型的属性。同时还有 offset 之类的边距属性。


重排是最耗能的,减少重排的方法有:


1、 如果需要多次改变 DOM,则先在内存中改变,最后一次性的插入到 DOM 中。


2、 同上一条,如果多次改变样式,合成一条,再插入 DOM 中。


3、 由于 position 的值为 absoute 和 fixed 时候,是脱离文档流的,操作此类 DOM 节点,不会引起整页重排。所以动画元素设置 position 使其脱离文档流。


4、 当 DOM 节点的 display 等于 none 的时候,是不会存在于渲染树的,所以如果有比较复杂的操作,先使其 display 等于 none,等待所有操作完毕后,再将 display 设成 block,这样就只重排两次。


5、 获取会导致重排的属性值时,存入变量,再次使用时就不会再次重排。获取这些属性会导致重排:offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight


以上就是浏览器如何把资源变成肉眼所见的页面的,除了上述根据浏览器流程而总结出来的性能优化,我们还需要看看 javascript 作为程序,需要的优化。先来看看 javascript 的垃圾回收机制。


Javascript 的引擎会在固定的时间间隔,将不再使用的局部变量注销掉,释放其所占的内存。而闭包的存在,将使引用一直存在,无法被释放掉。全局变量的生命周期直至浏览器卸载页面才会结束。所以一般来讲,内存溢出就是由于全局变量的不释放和闭包引起。为了防止内存溢出,我们可以做的方法有:


1、 业务代码放在匿名立即执行函数里面,执行完毕会立即释放掉。


2、 少用全局变量,同时用完的变量手动注销掉。


3、 使用回调来代替闭包访问内部属性


4、 当不可避免使用闭包时,慎重的对待其中的细节。不用的时候注销掉。


5、 通过浏览器自带的工具 profiles,来检查内存活动情况。如果是波浪型的,说明正常。如果是倾斜式渐进上涨的,说明有内存不会被释放,需要检查相应的函数。


最后再说一点,函数里返回异步取的值,经常有人这么:


Var getList = function(){ $.ajax().then(function(data){
Return data;
}) };
Var users = getList();
复制代码


毫无疑问,由于函数内的返回是异步的,所以返回只能是 undefined,而不是想要的 data。于是为了实现返回 data,就把 ajax 的 async 属性设置成了 false,由异步改为同步,来获取到 data。然而最大的问题来了,同步是会中断渲染进程的,也就是请求返回的等待中,整个页面是卡死的,用户操作也不会有响应。这个问题真正的解决方案是返回 promise 对象,而不是把异步改成同步。


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/143


2020-02-14 18:55951

评论

发布
暂无评论
发现更多内容

图解 K8S 源码 - Informer 篇

郭旭东

Kubernetes Kubernetes源码

企业开发遇到瓶颈,何不换个新思路?快速开发了解一下

Marilyn

敏捷开发 快速开发

WSDM Cup 2020大赛金牌参赛方案全解析

华为云开发者联盟

大数据 搜索 信息

年轻人大企打拼多年,刚升迁便遇巨大阻力难以解决,到底如何才能在职场中幸存?

Marilyn

敏捷开发 快速开发

来喽,来喽,Python 3.9正式版发布了~~~

华为云开发者联盟

Python 编程

医疗AI系统构建(1)one-hot编码

刘旭东

人工智能 学习 医疗AI one-hot

第三周作业一

dll

OKR-VUCA时代目标管理利器实践分享

张兆东

有了TA,领域外企业里的小IT团队,也能轻松搞定大型项目

Marilyn

敏捷开发 快速开发

高难度对话读书笔记—聆听篇

wo是一棵草

OpLog4j

Geek_746da6

一线城市年轻人生活工作实录(程序员篇)

Marilyn

敏捷开发 开发者工具 快速开发

华为云专家讲述知识图谱构建流程及方法

华为云开发者联盟

华为 数据 知识图谱

Programmatic Navigation using SwiftUI| 使用SwiftUI进行程序化导航

Daniel

一线城市年轻人生活工作录(业务员篇)

Marilyn

敏捷开发 快速开发

图扑软件联手阿里Lindorm数据库开启工业物联超融合存储模式

许力

IoT AIOT

The story of programmers in famous enterprises.

Marilyn

敏捷开发 快速开发

我和我的智能联接

脑极体

从哲学源头思考自动驾驶网络架构设计

华为云开发者联盟

自动驾驶 架构

拜托,学妹,别再问我怎么自学 Java 了!和盘托出

沉默王二

Java 自学编程

LeetCode题解:94. 二叉树的中序遍历,使用栈,JavaScript,详细注释

Lee Chen

大前端 LeetCode

亚马逊Prime会员日火爆开启一站购全球逾3000万正品商品

爱极客侠

JVM-技术专题-对象的实例化过程

洛神灬殇

Java JVM

微前端之如何拆解React巨石应用 qiankun

SugarTurboS

项目管理 架构 大前端 React

Lindorm云原生数据库 - 让数字时代IT运维系统“灵动”起来

许力

DevOps APM Data Lake AIOPS

JVM-技术专题-Java类文件结构

洛神灬殇

Java JVM

在线教育企业迎来“秋招”大考,数字用户体验成胜负关键手

博睿数据

运维 APM 在线教育 AIOPS 用户体验

苦难过后,终会团聚

hellocj

百度人工智能OCR调用调试过程

tuuezzy

国外的公司都是如何对待大龄程序员的?在国内该如何应对?

Java架构师迁哥

JVM-技术专题-类加载机制

洛神灬殇

Java JVM

浅析Web前端性能优化_行业深度_马宗泽_InfoQ精选文章