文档章节

Web表现层性能优化

weiliu007
 weiliu007
发布于 2016/09/30 09:07
字数 4126
阅读 44
收藏 0

我们先了解一下,从输入URL地址或者点击URL的一个链接到页面呈现的一次请求,大致需要下面几个步骤

1:查找DNS,解析出URL对应的IP地址
2:初始化网络连接
3:发送HTTP请求
4:网络传输请求到服务器
5:Web服务器接收到请求,经过处理转发到相应的Web应用
6:Web应用处理请求,并返回相应的应答
7:网络传输应答内容到前端浏览器
8:浏览器开始解析从服务器端返回的内容,开始渲染和绘制
9:根据HTML内容来构建DOM(文档对象模型)
10:加载和解析样式,构建CSSOM(CSS对象模型)
11:根据DOM和CSSOM来构建渲染树,这个过程是按照文档顺序从上到下依次进行的
12:会根据构建渲染树的过程,在适当的时候,把已经构建好的部分绘制到界面上,中间还会伴随着重
绘(repaint)和回流(reflow)等,如此循环操作,直到渲染绘制完成
13:整个页面加载完成,会触发OnLoad事件

简单分析一下上面这些步骤的这个过程:

1:要通过URL请求服务器,浏览器就要知道这个URL对应的IP是什么,只有知道了IP地址,浏
览器才能准备的把请求发送到指定的服务器的具体IP和端口号上面。浏览器的DNS解析器负
责把URL解析为正确的IP地址。
这个解析工作是要花时间的,而且这个解析的时间段内,浏览器不能从服务器那里
下载任何东西。浏览器和操作系统提供了DNS解析缓存支持。
2:当获得了IP地址之后,浏览器会请求与服务器的连接,TCP经过三次握手后建立连接通道
3:浏览器真正发送HTTP请求,这个请求包含了很多东西,如cookie和其他的head头信息。
4:网络开始传输请求到服务器,这个会包括很多时间,比如网络阻塞时间、网络延迟时间和
真正传输内容的时间等,这是个很复杂的过程
5:Web服务器接收到请求,会根据URL里面的上下文,转交给相应的Web应用进行处理
6:Web应用会依次通过很多处理,比如:filter、aop的前置处理、IoC处理、真实处理对象的
寻找和创建等,这个根据每个应用的具体实现而不同。然后会把请求转交到真实的处理对象,进行相应的业务处理,并生成Response对象

7:通过网络传输应答内容回到前端的浏览器。其实首先到达浏览器的是纯粹的html代码,不
包含什么图片,外部脚本,外部CSS等,也就是页面主要的html结构。
8:接下来就是浏览器解析页面,进行渲染和绘制的过程了,大致如下:
(1)装载和解析Html文档,构建DOM,如果在解析中发现需要其它的资源,比如图片,那么浏
览器会发出请求以获取这个资源
(2)装载和解析CSS,构建CSSOM
(3)根据DOM和CSSOM来构建渲染树
(4)然后对渲染树的节点进行布局处理,确定其在屏幕的位置
(5)把渲染好的节点绘制到界面上
以上步骤是一个渐进的过程,渲染引擎不会等到所有Html都被解析完才创建并布局
渲染树,它会在获取文档内容的同时把已经接收到的局部内容先展示出来。
9:重绘(repaint)的发生:如果渲染到后面,发现需要修改前面已经绘制元素的外观,比如
背景色、文字颜色等,不影响它周围和内部布局的行为,这就需要重绘这个元素
10:回流(reflow)的发生:如果渲染到后面,发现需要修改前面已经绘制好的元素的某些行
为,这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引
起它内部、周围甚至整个页面的重新渲染,这就是回流

什么是延迟
  延迟指的是:消息或分组从信息源发送到目的地所需的总时间
延迟的构成

1:传播延迟
指的是消息从发送端到接收端需要的时间,是信号传播距离和速度的函数。取决于
距离和信号通过的媒介。
2:传输延迟
指的是把消息中的bit转移到链路所需要的时间,是消息长度和链路速率的函数。取
决于链路的速率,跟客户端到服务器的距离无关。
3:处理延迟
指的是处理分组头部、检查位错误、确定分组目标所需要的时间。通常由硬件来完
成,如路由器要根据分组头部来选择出站路由。
4:排队延迟
指的是分组排队等待处理的时间。如果分组到达的速度超过了路由器的处理能力,
那么分组就要进入缓冲区排队。

DOM、CSSOM和JavaScript经常交织在一起:
1:脚本执行过程中可能会处理需要同步的功能,比如document.write,从而会阻塞DOM的解析
和构建;
2:脚本可能会查询任何对象的计算样式,从而阻塞CSS处理
结果就是DOM构建在JS执行完毕前无法进行,而JS在CSSOM构建完成前也无法进行。
浏览器对于HTML的解析是递增的,对于JavaScript和CSS的解析执行,要等到整个文
件下载完毕。

最基本的优化思路,大致来说:
1:尽量减少不必要的网络延迟
2:尽量减少请求数量
3:尽量减少来回传递的数据量
4:提高后台程序的响应速度
5:提高每个环节和步骤的处理能力,以加快速

Web性能的基本指标
1:请求响应时间:从客户端发起请求,到web应用对用户请求作出响应,再发送反馈直至用户
接收完毕所需要的时间,也被称为TTLB(Time to Last Byte),建议3/5/10秒。
2:最大并发用户数:用来衡量可用性,就是在不出现系统崩溃的情况下,能同时提供服务的
最大用户数量,通常分成两种:
(1)严格意义上的并发:即所有的用户在同一时刻做同样的操作
(2)广义的并发:多个用户同时进行了操作,但是这些操作可以是相同的,也可以是不同的
3:事务响应时间:是针对业务的概念,事务可能由一系列请求组成,以完成业务功能
4:TPS(Transaction Per Second):每秒钟系统能够处理的交易或者事务的数量,通用用来衡
量系统处理能力
5:吞吐量:在一次性能测试过程中,通过网络传输的数据量的总和。吞吐量/传输时间就是吞
吐率

Web性能测试的常见工具
1:用于测试页面资源加载速度,比如:
Firebug、Chrome的开发者工具、HttpWatch等
2:用于测试页面渲染呈现,以及js运行速度,比如:
dynaTrace Ajax、Speed Trace等
3:对页面进行整体评价分析,比如:
WebPageTest、Page Speed、yslow等
4:专业的测试工具,比如:
Selenium、WebLoad、ab、LoadRunner等

JavaScript的常见优化

1:尽量把JS放在页面底部
2:循环中要多次使用的表达式,比如:判断长度的表达式、获取对象的表达式,最
好在外面做个变量来保存
3:减少页面重绘,比如:不要在循环中改变元素外观,应该拼接好后,一次性的设
置给元素,这样就只需要重绘一次
4:尽量避免使用eval
5:把全局域的变量缓存成为局部域的变量,全局变量其实是window对象的成员,而
局部变量是放在函数的栈里的,局部变量访问更快
6:尽量避免对象的嵌套查询,比如:obj1.obj2.obj3这样的表达式就会引起多次查
找,应该把各个对象用局部变量缓存起来,这样后续使用就直接使用
7:当需要将数字转换成字符时,采用如下方式:“” + 数字的方式最快
8:当需要将浮点数转换成整型时,应该使用Math.floor()或者Math.round()。而不
是使用parseInt() ,Math是内部对象,速度是最快的

9:尽量让代码简洁,比如变量名、方法名在不影响语意的情况下尽量简单
10:连加多个字符串的,可以使用数组,把要连接的字符串放到数组中,然后使用
数组的join方法,形如:var str = myArr.join(“”);
11:尽量用JSON格式来创建对象,而不是var obj=new Object(),因为前者是直接
复制,而后者需要调用构造器
12:尽量使用JSON格式来创建数组,即直接使用:[parm,param,param...],而不是
采用 new Array(parm,param,param...)这种语法。因为使用JSON格式的语法是
引擎直接解释的。而后者则需要调用Array的构造器
13:尽量使用正则表达式来操作字符串,例如替换、查找等。因为JS的循环速度比
较慢,而正则表达式的操作是用C写成的API,性能比较好
14:对于大的JS对象,因为创建时时间和空间的开销都比较大,因此应尽量缓存
15:避免使用document.write,可以使用innerHTML来向页面添加对象
16:避免使用setTimeOut方法,应用setInterval,setTimeout每次要重置定时器
17:避免with语句,with会创建自已的作用域,会增加其中执行代码的作用域长度

18:尽量减少对DOM的操作,避免回流,引起回流的操作常见的有:
(1)改变窗体大小
(2)更改字体
(3)添加移除stylesheet块
(4)内容改变哪怕是输入框输入文字
(5)CSS虚类被触发如 :hover
(6)更改元素的className
(7)当对DOM节点执行新增或者删除操作或内容更改时
(8)动态设置一个style样式时
(9)当获取一个必须经过计算的CSS值时,比如访问offsetWidth、clientHeight等
为了避免回流的发生,建议:
(1)在对DOM进行操作之前,尽可能把多次操作内容准备好,然后尽量1次操作完成
(2)在对DOM操作之前,把要操作的元素,先从当前DOM结构中删除,等处理好过后再添加回
到DOM中。从DOM中删除元素的方法有:
A:通过removeChild()或者replaceChild()实现真正意义上的删除
B:设置该元素的display样式为“none”

(3)对获取的那些会触发回流操作的属性,比如offsetWidth等 缓存起来
(4)尽量避免通过style属性对元素的外观进行修改,因为会触发回流操作
A:使用更改className的方式替换style.xxx=xxx的方式
B:使用style.cssText = ‘’;一次写入样式
C: 避免设置过多的行内样式
(5)添加的结构外元素尽量设置它们的位置为fixed或absolute
(6)避免使用表格来布局
(7)避免在CSS中使用JavaScript表达式
19:对局部使用的JS,采用异步装载、按需装载JS的方式,比如使用jQuery的:
jQuery.getScript(“t.js”,function(){t1();});
这个是没有缓存js的,要缓存的话,如下:
jQuery.ajax({
   url: "t.js",
   dataType: "script",
   cache: true
}).done(function() {
    t1();
});

一,将脚本放在底部,脚本放在顶部带来的问题:
   1:使用脚本时,对于位于脚本以下的内容,逐步呈现将被阻塞
   2:在下载脚本时会阻塞并行下载
        放在底部,当脚本没加载进来,用户就触发脚本事件,可能会出现JS错误问题。
二, 将样式文件放在页面顶部
       样式表加载完成后,才会构建渲染树,因此样式文件放在页面底部可能会
   出现两种情况:
  1:白屏
  2:无样式内容的闪烁
三,CSS尽量写在<head>,不要出现在<body>中,否则会引起重新渲染
四 ,最小化 iframe 的数量
   iframe会导致重绘,同时iframe也是SEO的大忌。针对前端优化来说iframe
有其好处,可以异步和并发加载资源

五,减少DOM访问

查找DOM会花费时间,如果更改了位置和外观,可能会引起重绘和回流,建议:
1:使用临时变量(或数组)缓存已经访问过的元素
2:“离线”更新节点, 再将它们添加到树中
3:避免使用 JavaScript 输出页面布局--应该是 CSS 的事儿
4:批量操作时,使用字符串拼接,用innerHTML开销更小,速度更快,同时内存
也更安全

六,避免不必要的渲染

(1)position:fixed:fixed定位在滚动时会不停的进行渲染,特别是如果是页面
顶部有个fiexd,页面底部有个类似返回顶部的fixed,则在滚动时会整个页面进
行渲染,效率非常低。可以加transform: translateZ(0);解决。
(2)hover 特效:建议页面滚动时,先取消hover效果,滚动停止后再加上hover效
果。这个可以通过在外层加类名进行控制
(3)应该设置border:none,而不是border:0,设置为0,仍然是会渲染的

七,使用 <link> 而不是@importChoose,在 IE 中 @import 指令等同于把 link 标记写在 HTML 的底部。
八, 所有图片都应该指定高宽属性,否则浏览器会重新渲染网页
九, 尽量少用帧数过多过快的FLASH,GIF动画
十, 尽量避免使用CSS子选择符,CSS子选择符会造成一次浏览器的筛选和定位计算,
比如能用.div 的,就尽量不要用.nav ul li a .div 这样的写法
十一, 尽量避免渲染过程的”中断”,比如等待js的执行
十二, 不要在 HTML 中使用缩放图片
十三,避免使用 CSS 表达式

(1)position:fixed:fixed定位在滚动时会不停的进行渲染,特别是如果是页面
顶部有个fiexd,页面底部有个类似返回顶部的fixed,则在滚动时会整个页面进
行渲染,效率非常低。可以加transform: translateZ(0);解决。
(2)hover 特效:建议页面滚动时,先取消hover效果,滚动停止后再加上hover效
果。这个可以通过在外层加类名进行控制
(3)应该设置border:none,而不是border:0,设置为0,仍然是会渲染的

现代的浏览器会做很多优化,典型如:

1:资源预取和排定优先次序
2:DNS预解析
3:TCP预连接
4:页面预渲染
为了更好的利用浏览器的这些机制,我们可以:
1:CSS和JavaScript等重要资源应该尽早在文档中出现
2:应该尽早交付CSS,从而避免渲染阻塞并让JavaScript执行
3:非关键性的JavaScript应该推迟,以避免阻塞DOM和CSSDOM的构建
我们可以在文档中嵌入提示,以触发浏览器为我们采用其他优化机制
1:预解析特定域名,如:<link rel=“dns-prefetch” href=“//abc.com”>
2:预先获取页面后面要用的资源,如:<link rel=“subresource” href=“/js/a.js”>
3:预先获取将来导航要用的资源,如:<link rel=“prefetch” href=“/img/a.jpg”>
4:根据对用户下一个目标的预测,预渲染特定页面,如:<link rel=“prerender”
href=“//abc.com/a/b/d.html”>
这些提示会触发浏览器的优化机制,如果浏览器不支持,会当成空操作,没有害处

 

© 著作权归作者所有

共有 人打赏支持
weiliu007
粉丝 14
博文 171
码字总数 84766
作品 0
深圳
程序员
Net分布式系统之一:系统整体框架介绍

原文出处:Andon 一、设计目的   从事.Net平台开发系统已有8年多了,一直思考搭建.Net分布式系统架构。基于window平台搭建的大型分布式系统不多,之前了解过myspace、stackoverflow等大型网...

Andon
2016/05/18
0
0
Web框架--Jdon Framework

Jdon Framework(简称JF)是一套适合开发中小型J2EE/JavaEE应用系统的轻量Web框架(Lightweight Java Web Framework)。是国人独立开发的中国人自己的框架产品,2005年入选全球SUN公司网站jav...

匿名
2008/09/07
13.8K
1
Web系统开发构架再思考-前后端的完全分离

原文:Web系统开发构架再思考-前后端的完全分离 前言   前后端完全分离其实一直是Web开发人员的梦想,也一直是我的梦想,遥想当年,无论是直接在代码里面输出HTML,还是在HTML里面嵌入各种代码,...

杰克.陈
2017/12/16
0
0
细说五层网站架构

目前网站架构一般分为网页缓存层、负载均衡层、Web层和数据库层、文件服务器层。我们可以依次用这五层对网站架构进行讨论,为了增强说服力,我将用如下三个并发较大的生产环境来说明。 q 电子...

Bgxuliangwei
2015/12/21
0
0
基于NodeJS的全栈式开发

随着不同终端(Pad/Mobile/PC)的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,我们往往需要针对不同的终端开发定制的版本。为了提升开发效率,前后端分...

唐僧他大叔
2015/02/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何通过 J2Cache 实现分布式 session 存储

做 Java Web 开发的人多数都会需要使用到 session (会话),我们使用 session 来保存一些需要在两个不同的请求之间共享数据。一般 Java 的 Web 容器像 Tomcat、Resin、Jetty 等等,它们会在...

红薯
今天
3
0
C++ std::thread

C++11提供了std::thread类来表示一个多线程对象。 1,首先介绍一下std::this_thread命名空间: (1)std::this_thread::get_id():返回当前线程id (2)std::this_thread::yield():用户接口...

yepanl
今天
3
0
Nignx缓存文件与动态文件自动均衡的配置

下面这段nginx的配置脚本的作用是,自动判断是否存在缓存文件,如果有优先输出缓存文件,不经过php,如果没有,则回到php去处理,同时生成缓存文件。 PHP框架是ThinkPHP,最后一个rewrite有关...

swingcoder
今天
2
0
20180920 usermod命令与用户密码管理

命令 usermod usermod 命令的选项和 useradd 差不多。 一个用户可以属于多个组,但是gid只有一个;除了gid,其他的组(groups)叫做扩展组。 usermod -u 1010 username # 更改用户idusermod ...

野雪球
今天
3
0
Java网络编程基础

1. 简单了解网络通信协议TCP/IP网络模型相关名词 应用层(HTTP,FTP,DNS等) 传输层(TCP,UDP) 网络层(IP,ICMP等) 链路层(驱动程序,接口等) 链路层:用于定义物理传输通道,通常是对...

江左煤郎
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部