⑴ Mac下的webstorm占内存问题/webstorm卡顿
(摘自互联网)
第一步:检查Mac内存占用情况
1、点击右上角的搜索,搜索活动监视器,双击图标打开
2、可以查看webstorm使用的时候占内存基本是排第一的,尤其是在使用webstorm的iTerm命令窗口操作的时候(我是在使用npm安装Gulp插件),然后我的本本开始键盘发热(右上角更明显),有很明显的风扇转动的声音,这个时候察觉到内存不足CPU占用太高。(ps:所有还是推荐用Mac自带ITerm)
3、查看webstorm的占用内存配置文件,打开Finder选择Application应用程序,找到webstorm右键,选择显示包内容
路径:content/bin,选择webstorm.vmoptions(有的是idea.vmoptions这个文件?)
第二步,将webstorm不需要用到的插件关掉
第三步:修改webstorm使用内存参数,防止卡顿或者闪退(修改阈值减少所占内存比例并不是减少内存数值)
1、选择webstorm.vmoptions这个文件用webstorm打开
默认参数是
-Xms128m
-Xmx750m
-XX:MaxPermSize=350m
-XX:ReservedCodeCacheSize=240m
-XX:+UseCompressedOops
-javaagent:JetbrainsCrack.jar
2、修改前两个数值为:
-Xms512m
-Xmx2048m
-XX:MaxPermSize=350m
-XX:ReservedCodeCacheSize=240m
-XX:+UseCompressedOops
-javaagent:JetbrainsCrack.jar
可能遇到的问题,会弹出窗口询问是否修改当前文件。因为不是当前打开项目中的文件,是其他文件,软件有弹出警告框询问是都修改,这个时候选择OK确认就可以。
修改成功!
在前端开发中,性能一直都是被大家所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。 其中提高网页反应速度的一个方式就是使用缓存 。缓存技术一直一来在WEB技术体系中扮演非常重要角色,是快速且有效地提升性能的手段。
一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。
所以,缓存技术是无数WEB开发从业人员在工作过程中不可避免的一大问题。 在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度 。了解浏览器的缓存命中原理,是开发WEB应用的基础,本文着眼于此,学习浏览器缓存的相关知识,总结缓存避免和缓存管理的方法,结合具体的场景说明缓存的相关问题。希望能对有需要的人有所帮助。
在实际WEB开发过程中,缓存技术会涉及到不同层、不同端,比如:用户层、系统层、代理层、前端、后端、服务端等, 每一层的缓存目标都是一致的,就是尽快返回请求数据、减少延迟 ,但每层使用的技术实现是各有不同,面对不同层、不同端的优劣,选用不同的技术来提升系统响应效率。所以,我们首先看下各层的缓存都有哪些技术,都缓存哪些数据,从整体上,对WEB的缓存技术进行了解,如下图所示:
本篇文章重点讲的就是上面红色框部分缓存内容。
当浏览器请求一个网站的时候,会加载各种各样的资源,比如:HTML文档、图片、CSS和JS等文件。对于一些不经常变的内容,浏览器会将他们保存在本地的文件中,下次访问相同网站的时候,直接加载这些资源,加速访问。
那么如何知晓浏览器是读取了缓存还是直接请求服务器?如下图网站来做个示例:
第一次打开该网站后,如果再次刷新页面。会发现浏览器加载的众多资源中,有一部分size有具体数值,然而还有一部分请求,比如图片、css和js等文件并没有显示文件大小,而是显示了 from dis cache 或者 from memory cache 字样。这就说明了,该资源直接从本地硬盘或者浏览器内存读取,而并没有请求服务器。
浏览器启用缓存至少有两点显而易见的好处: (1)减少页面加载时间;(2)减少服务器负载;
浏览器是否使用缓存、缓存多久,是由服务器控制的 。准确来说,当浏览器请求一个网页(或者其他资源)时, 服务器发回的响应的“响应头”部分的某些字段指明了有关缓存的关键信息 。下面看下,HTTP报文中与缓存相关的首部字段:
根据上面四种类型的首部字段不同使用策略, 浏览器中缓存可分为强缓存和协商缓存 :
当浏览器对某个资源的请求命中了强缓存时, 返回的HTTP状态为200 ,在chrome的开发者工具的network里面 size会显示为from cache ,比如:京东的首页里就有很多静态资源配置了强缓存,用chrome打开几次,再用f12查看network,可以看到有不少请求就是从缓存中加载的:
Expires是HTTP 1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示 ,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,包含了Expires头标签的文件,就说明浏览器对于该文件缓存具有非常大的控制权。
例如,一个文件的Expires值是2020年的1月1日,那么就代表,在2020年1月1日之前,浏览器都可以直接使用该文件的本地缓存文件,而不必去服务器再次请求该文件,哪怕服务器文件发生了变化。
所以, Expires是优化中最理想的情况,因为它根本不会产生请求 ,所以后端也就无需考虑查询快慢。它的缓存原理,如下:
Expires是较老的强缓存管理header, 由于它是服务器返回的一个绝对时间 ,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题, 比如:随意修改下客户端时间,就能影响缓存命中的结果 。所以在HTTP 1.1的时候,提出了一个新的header, 就是Cache-Control,这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示 ,如:Cache-Control:max-age=315360000,它的缓存原理是:
Cache-Control描述的是一个相对时间 ,在进行缓存命中的时候, 都是利用客户端时间进行判断 ,所以相比较Expires,Cache-Control的缓存管理更有效,安全一些。
这两个header可以只启用一个,也可以同时启用, 当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires :
此外,还可以为 Cache-Control 指定 public 或 private 标记。 如果使用 private,则表示该资源仅仅属于发出请求的最终用户,这将禁止中间服务器(如代理服务器)缓存此类资源 。对于包含用户个人信息的文件(如一个包含用户名的 HTML 文档),可以设置 private,一方面由于这些缓存对其他用户来说没有任何意义,另一方面用户可能不希望相关文件储存在不受信任的服务器上。需要指出的是,private 并不会使得缓存更加安全,它同样会传给中间服务器(如果网站对于传输的安全性要求很高,应该使用传输层安全措施)。 对于 public,则允许所有服务器缓存该资源 。通常情况下,对于所有人都可以访问的资源(例如网站的 logo、图片、脚本等), Cache-Control 默认设为 public 是合理的 。
当浏览器对某个资源的请求没有命中强缓存, 就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串 ,比如你打开京东的首页,按f12打开开发者工具,再按f5刷新页面,查看network,可以看到有不少请求就是命中了协商缓存的:
查看单个请求的Response Header, 也能看到304的状态码和Not Modified的字符串,只要看到这个就可说明这个资源是命中了协商缓存,然后从客户端缓存中加载的 ,而不是服务器最新的资源:
【Last-Modified,If-Modified-Since】的控制缓存的原理,如下 :
【Last-Modified,If-Modified-Since】都是根据服务器时间返回的header,一般来说, 在没有调整服务器时间和篡改客户端缓存的情况下,这两个header配合起来管理协商缓存是非常可靠的,但是有时候也会服务器上资源其实有变化,但是最后修改时间却没有变化的情况 ,而这种问题又很不容易被定位出来,而当这种情况出现的时候,就会影响协商缓存的可靠性。 所以就有了另外一对header来管理协商缓存,这对header就是【ETag、If-None-Match】 。它们的缓存管理的方式是:
Etag和Last-Modified非常相似,都是用来判断一个参数,从而决定是否启用缓存。 但是ETag相对于Last-Modified也有其优势,可以更加准确的判断文件内容是否被修改 ,从而在实际操作中实用程度也更高。
协商缓存跟强缓存不一样,强缓存不发请求到服务器, 所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器 ,所以资源是否更新,服务器肯定知道。大部分web服务器都默认开启协商缓存,而且是同时启用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,比如apache:
如果没有协商缓存,每个到服务器的请求,就都得返回资源内容,这样服务器的性能会极差。
【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】一般都是同时启用,这是为了处理Last-Modified不可靠的情况。有一种场景需要注意:
比如,京东页面的资源请求,返回的repsonse header就只有Last-Modified,没有ETag:
协商缓存需要配合强缓存使用,上面这个截图中,除了Last-Modified这个header,还有强缓存的相关header, 因为如果不启用强缓存的话,协商缓存根本没有意义 。
如果资源已经被浏览器缓存下来,在缓存失效之前,再次请求时,默认会先检查是否命中强缓存,如果强缓存命中则直接读取缓存,如果强缓存没有命中则发请求到服务器检查是否命中协商缓存,如果协商缓存命中,则告诉浏览器还是可以从缓存读取,否则才从服务器返回最新的资源。其浏览器判断缓存的详细流程图,如下:
⑶ 1 如何优化Tomcat
(1)bin:主要用来存放命令,.bat是windows下,.sh是Linux下
(2)conf:主要用来存放tomcat的一些配置文件
(3)lib:存放tomcat依赖的一些jar包
(4)logs:存放tomcat在运行时产生的日志文件
(5)temp:存放运行时产生的临时文件
(6)webapps:存放应用程序
(7)work:存放tomcat运行时编译后的文件,比如JSP编译后的文件
tomcat优化可以有几个方向:配置项的删除,配置参数的修改,jdk参数修改、Tomcat内存优化、Tomcat并发优化、Tomcat缓存优化
web项目中自带的WEB-INF/web.xml,
tomcat自带的conf/web.xml以及conf/server.xml文件。
因为这些xml文件都会被tomcat解析,所以优化方向是将这三类文件中不必要的配置删除。
tomcat在启动时,会将web项目中WEB-INF/web.xml和自己的conf/web.xml进行合并,然后在ContextConfig类下的configureContext()统一解析这些内容:
这个只能是在项目中不需要的配置不要放进去,有过期的配置要及时删除,减少tomcat的解析成本。
这是一个处理静态文件的servlet,如果项目中不需要tomcat进行静态文件的处理,可以将其删掉。
这个servlet是用来编译和执行jsp文件的,如果项目中没有jsp文件,可以将其删掉。
项目中没有jsp,关于jsp下面的映射也可以删除:
文件中提供的mime类型非常多,如果有确定项目中不会涉及到的类型,可以删除其映射配置。
如果不需要展示tomcat的欢迎页,可以将其删掉。
下面是tomcat8.5版本提供的默认listener列表:
作用是在Tomcat初始化时,打印一下Tomcat相关的版本信息以及操作系统和jdk环境信息,可以删掉。
Tomcat启动时,检查APR库,如果存在则加载,这个配置仅当connector的protocol设置为AJP/1.3时有用,如果非AJP/1.3,可以删除。
Java运行环境可能导致某些已知位置的内存泄漏或文件锁定,
提供这些情况的解决方案。
作用于全局资源,通过该监听器,初始化标签中定义的全局JNDI资源;
如果没有该监听器,定义的全局资源都不能使用。
如果不使用GlobalNamingResources定义全局资源,可以删除。
Web应用因thread-local导致的内存泄露而要停止时,该监听器会触发线程池中线程的更新。
只有当Web应用(即Context元素)的属性设置为true时,该监听器才有效。
官方文档对配置的解释为:
GlobalNamingResources可以定义全局资源,可以看出,这个tomcat的默认配置是通过读取$TOMCAT_HOME/ conf/tomcat-users.xml实现的。
tomcat-user.xml用于定义tomcat管理页面相关配置,如果不登录管理界面可以删掉。
官网中对于这个connector有如下描述:
The AJP Connector element represents a Connector component that communicates with a web connector via the AJP protocol. This is used for cases where you wish to invisibly integrate Tomcat into an existing (or new) Apache installation, and you want Apache to handle the static content contained in the web application, and/or utilize Apache's SSL processing.
可知当tomcat需要集成到Apache服务器时才使用这个connector,现在一般都用Nginx代替Apache,所以不使用Apache的话这个也可以删掉。
tomcat默认配置包含如下connector:
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
Realm,可以把它理解成“域”;
Realm提供了一种用户密码与web应用的映射关系,从而达到角色安全管理的作用,tomcat默认的这个realm是和name为UserDatabase的资源绑定的,而该资源在Server元素中使用GlobalNamingResources配置。如果不需要可以删掉。
Valve的意思是“阀门”,不同的Valve有不同的特性,Valve的配置中AccessLogValve的作用是记录其所在容器处理的所有请求,默认配置中的Valve放在Host下,便可以记录该Host处理的所有请求。
AccessLogValve记录的日志就是访问日志,每天的请求会写到一个日志文件里。现在一般记录Nginx访问日志,这个也可以删除。
tomcat是用Java写的,就要运行在jvm上,垃圾处理方式等都要遵循jvm的方式。
tomcat中设置jvm参数在 catalina.sh(Linux)和catalina.bat(windows)中,以JAVA_OPTS变量存储。以catalina.sh为例:
可以在该变量中添加jvm参数,达到减少gc次数等目标,例如根据tomcat所在服务器修改jvm内存大小等。
参数优化主要是优化sever.xml中的配置参数,示例server.xml如下:
port:指定一个端口,这个端口负责监听关闭tomcat的请求。
shutdown:指定向端口发送的命令字符串。
sever配置没什么可优化的。
name:指定service的名字。
service配置没什么可优化的。
port:指定服务器端要创建的端口号,并在这个端口监听来自客户端的请求
minProcessors:服务器启动时创建的处理请求的线程数
maxProcessors:最大可以创建的处理请求的线程数
enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址
redirectPort:指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
maxConnections:达到这个值之后,将继续接受连接,但是不处理,能继续接受多少根据acceptCount的值
minSpareThreads:最小空闲线程数
connectionTimeout:指定超时的时间数(以毫秒为单位)
官网8.5版本connector使用连接类型如下:
查看Connector源码:
可知默认协议使用的是Http11NioProtocol,即NIO方式。
tomcat默认连接池有限制,可以为connector配置自己的连接池,例如:
在连接池中可以根据项目自定义最大线程数量。
name:属性用于日志和错误信息,在整个Server中应该唯一
defaultHost:defaultHost属性指定了默认的host名称,当发往本机的请求指定的host名称不存在时,一律使用defaultHost指定的host进行处理;因此defaultHost的值,必须与Engine中的一个Host组件的name属性值匹配
没什么可优化的。
name:指定虚拟主机的主机名,一个Engine中有且仅有一个Host组件的name属性与Engine组件的defaultHost属性相匹配;
注:一般情况下,主机名需要是在DNS服务器中注册的网络名,但是Engine指定的defaultHost不需要
appBase:应用程序基本目录,即存放应用程序的目录
unpackWARs:指定了是否将war文件解压,如果为true,则通过解压后的目录运行该Web应用;如果为false,则直接使用WAR文件运行Web应用
autoDeploy:是否自动部署,Tomcat运行期间会用一个线程定时检查,如果有新的web工程会自动部署。
autoDeploy生产环境之下可以改成false,减少tomcat的负担。
autoDeploy有需要注意的点,如果为true,拷贝war到webapp下面,tomcat自动解压并部署。但是停掉tomcat拷贝新的war包过去,tomcat不会解压新包并后覆盖旧目录,因为tomcat直接使用了之前解压过的目录。官网有描述:
If you redeploy an updated WAR file, be sure to delete the expanded directory when restarting Tomcat, so that the updated WAR file will be re-expanded (note that the auto deployer, if enabled, will automatically expand the updated WAR file once the previously expanded directory is removed).
docBase:代表应用程序或war文件存放的路径,这个可以自由指定,例如d:/study
path:
表示此web应用程序的url的前缀,这样请求的url为 http://localhost:8080/path/ **
reloadable:如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib和/WEB-INF/classes目录的变化,自动装载新的应用程序,可以在不重起tomcat的情况下改变应用程序
生产环境中可以把reloadable设置为false。
className:指定Realm使用的类名,此类必须实现org.apache.catalina.Realm接口
没什么可优化的
className:规定了Valve的类型;例如tomcat默认的是AccessLogValve。
directory:指定日志存储的位置,默认日志存储在 TOMCAT_HOME/logs目录下,可以看到如下所示的日志文件。
没什么可优化的。
Tomcat内存优化主要是对 tomcat 启动参数优化,我们可以在 tomcat 的启动脚本 catalina.sh 中设置 java_OPTS 参数。
现公司服务器内存一般都可以加到最大2G ,所以可以采取以下配置:
JAVA_OPTS=’-Xms1024m -Xmx2048m -XX: PermSize=256M -XX:MaxNewSize=256m -XX:MaxPermSize=256m’
配置完成后可重启Tomcat ,通过以下命令进行查看配置是否生效:
首先查看Tomcat 进程号:sudo lsof -i:9027
我们可以看到Tomcat 进程号是 12222 。
查看是否配置生效:sudo jmap – heap 12222
我们可以看到MaxHeapSize 等参数已经生效。
在Tomcat 配置文件 server.xml 中的
<Connector port="9027"
protocol="HTTP/1.1"
maxHttpHeaderSize="8192"
minProcessors="100"
maxProcessors="1000"
acceptCount="1000"
redirectPort="8443"
disableUploadTimeout="true"/>
maxThreads 客户请求最大线程数
minSpareThreads Tomcat初始化时创建的 socket 线程数
maxSpareThreads Tomcat连接器的最大空闲 socket 线程数
enableLookups 若设为true, 则支持域名解析,可把 ip 地址解析为主机名
redirectPort 在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
acceptAccount 监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads )
connectionTimeout 连接超时
minProcessors 服务器创建时的最小处理线程数
maxProcessors 服务器同时最大处理线程数
URIEncoding URL统一编码
compression 打开压缩功能
compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB
compressableMimeType 压缩类型
connectionTimeout 定义建立客户连接超时的时间. 如果为 -1, 表示不限制建立客户连接的时间
⑷ 网站性能优化有哪些
一、提高服务器并发处理能力
我们总是希望一台服务器在单位时间内能处理的请求越多越好,这也成了web服务器的能力高低的关键所在。服务器之所以可以同时处理多个请求,在于操作系统通过多执行流体系设计,使得多个任务可以轮流使用系统资源,这些资源包括CPU、内存以及I/O等。这就需要选择一个合适的并发策略来合理利用这些资源,从而提高服务器的并发处理能力。这些并发策略更多的应用在apache、nginx、lighttpd等底层web server软件中。
二、Web组件分离
这里所说的web组件是指web服务器提供的所有基于URL访问的资源,包括动态内容,静态网页,图片,样式表,脚本,视频等等。这些资源在文件大小,文件数量,内容更新频率,预计并发用户数,是否需要脚本解释器等方面有着很大的差异,对不同特性资源采用能充分发挥其潜力的优化策略,能极大的提高web站点的性能。例如:将图片部署在独立的服务器上并为其分配独立的新域名,对静态网页使用epoll模型可以在大并发数情况下吞吐率保持稳定。
三、数据库性能优化和扩展。
Web服务器软件在数据库方面做的优化主要是减少访问数据库的次数,具体做法就是使用各种缓存方法。也可以从数据库本身入手提高其查询性能,这涉及到数据库性能优化方面的知识本文不作讨论。另外也可以通过主从复制,读写分离,使用反向代理,写操作分离等方式来扩展数据库规模,提升数据库服务能力。
四、Web负载均衡及相关技术
负载均衡是web站点规模水平扩展的一种手段,实现负载均衡的方法有好几种包括基于HTTP重定向的负载均衡,DNS负载均衡,反向代理负载均衡,四层负载均衡等等。
对这些负载均衡方法做简单的介绍:基于HTTP重定向的负载均衡利用了HTTP重定向的请求转移和自动跳转功能来实现负载均衡,我们熟悉的镜像下载就使用这种负载均衡。DNS负载均衡是指在一个DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时返回不同的解析结果将客户端的访问引到不同的机器上,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。反向代理负载均衡也叫七层负载均衡,这是因为反向代理服务器工作在TCP七层结构的第七层(应用层),它通过检查流经的HTTP报头,根据报头内的信息来执行负载均衡任务。四层负载均衡是基于NAT技术的负载均衡,它将一个Internet上合法注册的IP地址映射为多个内部服务器的IP地址,对每次TCP连接请求动态使用其中一个内部IP地址,达到负载均衡的目的。此外,还有工作在数据链路层(第二层)的直接路由方式下的负载均衡,它通过修改数据包目标MAC地址来实现。以及,基于IP隧道的负载均衡,在这种方式下可以将实际服务器根据需要部署在不同的地域,并根据就近访问的原则来转移请求,CDN服务便是基于IP隧道技术来实现的。
Web负载均衡在扩展web服务器规模的同时也给web站点性能优化提供了一个更大更复杂也更灵活自由的平台,基于该平台性能优化的策略包括共享文件系统,内容分发与同步,分布式文件系统,分布式计算,分布式缓存等等。
五、web缓存技术
web缓存技术被认为是减轻服务器负载、降低网络拥塞、增强万维网可扩展性的有效途径,其基本思想是利用客户访问的时间局部性(Temporal Locality)原理,将客户访问过的内容在Cache中存放一个副本,当该内容下次被访问时,不必连接到驻留网站或重新计算生成,而是由Cache中保留的副本提供。Web缓存可以带来如下的好处:
(1) 减少网络流量,从而减轻网络拥塞;这是因为缓存避免了一部分HTTP请求。
(2) 降低客户访问延迟,其主要原因有:①已缓存的内容,客户可以缓存获取而不是从服务器获取或重新计算生成,从而减小了传输延迟缩短了响应时间;②没有被缓存的内容由于网络拥塞及服务器负载的减轻而可以较快地被客户获取;
(3) 由于客户的部分或者全部请求内容可以从通过缓存获取,从而减轻了远程服务器负载。
(4) 如果由于服务器故障或网络故障造成服务器无法响应客户请求,客户可以从缓存中获取缓存的内容副本,使得web站点服务的鲁棒性(Robustness)得到了加强。
可以看出web缓存能给web站点带可观的性能提升。其实在用户发出请求到一幅完整的网页呈现在用户面前这一过程中缓存无处不在,下面是web性能优化时常用的缓存技术,你会发现缓存被广泛应用在各个环节。
浏览器缓存:浏览器一般会在用户文件系统中创建一个目录,用于存放缓存文件,并给每个缓存文件打上必要的标记,比如过期时间等。这些标记主要用于浏览器和服务器之间的缓存协商。
Web服务器缓存:一个URL在一段较长时间内对应一个唯一的响应内容,比如静态内容或者更新不太频繁的动态内容,web服务器可将响应内容缓存起来,下次web服务器便可以在收到请求后立即拿出事先缓存好的响应内容并返回给浏览器。
代理服务器缓存:暴露在互联网中与后端的web服务器通过内部网络相连的前端服务器称为反向代理服务器,建立在反向代理服务器上的缓存称为反向代理缓存。暴露在互联网中与后端的web客户端通过内部网络相连的前端服务器称为正向代理服务器,建立在正向代理服务器上的缓存称为正向代理缓存。代理服务器缓存位于客户端和web服务器之间,可以将它看做二者之间的一个中继站。它的存在可以改善客户端的访问速度、提升web server的服务能力、安全性等等。
总共分析总结了五种技术,主要希望能够对web server性能优化这块提供一个整体的认识。后续会专门就web缓存技术发表一些自己的看法。
⑸ Web前端性能优化的实用技巧汇总
今天小编要跟大家分享的文章是关于Web前端性能优化的实用技巧汇总。javascript在浏览器中运行的性能,可以认为是开发者所面临的最严重的可用性问题。这个问题因为javascript的阻塞性而变得复杂,事实上,多数浏览器使用单一进程来处理用户界面和js脚本执行,所以同一时刻只能做一件事。js执行过程耗时越久,浏览器等待响应的时间越长。
一.提高加载性能
1.IE8,FF,3.5,Safari4和Chrome都允许并行下载js文件,当script下载资源时不会阻塞其他script的下载。但是js下载仍然会阻塞其他资源的下载,如图片。尽管脚本下载不会互相影响,但页面仍然必须等待所有塌尘岩js代码下载并执行完才能继续。因兄雹此仍然存在脚本阻塞问题.推荐将所有js文件放在body标签底部以减少对整个页面的影响。
2.减少页面外链脚本文件的数量将会提高页面性能:
http请求会带来额外的开销,因此下载单个300k的文件将比下载10个30k的文件效率更高。
3.动态脚本加载技术:
无论何时启动下载,文件的下载和执行都不会阻塞页面其他进程。
functionlaodScript(url,callback){
varscript=document.createElement('script');_
_cript.type='text/javascript'__f(script.readyState){//ie
____cript.onreadystatechange=function(){_____
if(script.readyState=='loaded'||script.readyState=='complete'){_______
_cript.onreadystatechange=null;_______
callback()_____
____
__
}else{//其他浏览器___
script.onload=function(){_____
_allback()
___}_
}_
script.src=url;_
document.getElementsByTagName('head')[0].appendChild(script);
}
//使用
loadScript('./a.js',function(){_
loadScript('./b.js',function(){___
loadScript('./c.js',function(){_____
console.log('加载完成')___
})_
})
})
4.无阻塞加载类库——LABjs,使用方法如下:
//链式调用时文件逐个下载,.wait()用来指定文件下载并执行完毕后所调用的函数
$LAB.script('./a.js')_
.script('./b.js')_
.wait(function(){__
_pp.init();
})
//为了保证执行顺序,可以这么做,此时a必定在b前执行
$LAB.script('./a.js').wait()_
.script('./b.js')_
.wait(function(){___
_pp.init();
})
二.数据存取与JS性能
1.在js中,数据存储的位置会对代码整体性能产生重大影响。数据存储共有4种方式:字面量,变量,数组项,对象成员。他们有着各自的性能特点。
2.访问字面量和局部变量的速度最快,相反,访问数组和对象相对较慢
3.由于局部变量存在于作用域链的起始位置,因此访问局部变量的比访问跨域作用变量更快
4.嵌套的对象成员会明显影响性能,应尽量避免
5.属性和方法在原型链位置越深,访问他的速度越慢
6.通常我们可以把需要多次使用的对象成员,数组元素,跨域变量保存在局部变量中来改善js性能
三.DOM编程
1.访问DOM会影响浏览器性能,修改DOM则更耗费性能,因为他会导致浏览器重新计算页面的几何变化。<通常的做法是减少访问DOM的次数,把运算尽量留在JS这一端。
注团御:如过在一个对性能要求比较高的操作中更新一段HTML,推荐使用innerHTML,因为它在绝大多数浏览器中运行的都很快。但对于大多数日常操作而言,并没有太大区别,所以你更应该根据可读性,稳定性,团队习惯,代码风格来综合决定使用innerHTML还是createElement()
2.HTML集合优化
HTML集合包含了DOM节点引用的类数组对象,一直与文档保持连接,每次你需要最新的信息时,都会重复执行查询操作,哪怕只是获取集合里元素的个数。
①_优化一——集合转数组collToArr
functioncollToArr(coll){_
for(vari=0,a=[],len=coll.length;i
a._ush(coll[i]);
__
returna
}
②缓存集合length
③访问集合元素时使用局部变量(即将重复的集合访问缓存到局部变量中,用局部变量来操作)
3.遍历DOM
①使用只返回元素节点的API遍历DOM,因为这些API的执行效率比自己实现的效率更高:
td{border:1pxsolid#ccc;padding:5px;margin:auto;}
td>p{text-align:left;}
td>pspan{text-align:center;display:block;}
属性名
被替代属性
children
childNodes
childElementCount
childNodes.length
firstElementChild
firstChild
lastElementChild
lastChild
nextElementSibling
nextSibling
previousElementSibling
previousSibling
_谘≡衿_PI——querySelectorAll()
querySelectorAll()方法使用css选择器作为参数并返回一个NodeList——包含着匹配节点的类数组对象,该方法不会返回HTML集合,因此返回的节点不会对应实时文档结构,着也避免了HTML集合引起的性能问题。
let_rr=_ocument.querySelectorAll('div.warning,_iv.notice>_')
4.重绘和重排
浏览器在下载完页面的所有组件——html,js,css,图片等之后,会解析并生成两个内部数据结构——_OM树,渲染树.一旦DOM树和渲染树构建完成,浏览器就开始绘制页面元素(paint).
①重排发生的条件:
添加或删除可见的DOM元素位置变化元素尺寸改变内容改变页面渲染器初始化浏览器窗口尺寸变化出现滚动条时会触发整个页面的重排_嘏疟囟ㄖ鼗
5.渲染树变化的排列和刷新
大多数浏览器通过队列化修改并批量执行来优化重排过程,然而获取布局信息的操作会导致队列强制刷新。
offsetTop,offsetWidth...
scrollTop,scrollHeight...
clientTop,clientHeight...
getComputedStyle()
一些优化建议:将设置样式的操作和获取样式的操作分开:
//设置样式
body.style.color='red'
body.style.fontSize=པpx'
//读取样式
letcolor=body.style.color
let_ontSize=_ody.style.fontSize
另外,获取计算属性的兼容写法:
functiongetComputedStyle(el){_
varcomputed=(document.body.currentStyle?el.currentStyle:document.defaultView.getComputedStyle(el,'');_
returncomputed
}
6.最小化重绘和重排
①.批量改变样式
/*使用cssText
*/el.style.cssText='border-left:1px;_order-right:2px;_adding:20px'
②.批量修改dom的优化方案——使元素脱离文档流-对其应用多重改变-把元素带回文档
functionappendDataToEl(option){
vartargetEl=option.target||document.body,___
createEl,___
data=option.data||[];_//让容器脱离文档流,减少重绘重排_
vartargetEl_display=targetEl.style.display;_
targetEl.style.display='none'
_
//*****创建文档片段来优化Dom操作****_
varfragment=document.createDocumentFragment();_//给元素填充数据_
for(vari=0,max=data.length;i
createEl=
document.createElement(option.createEl);___
for(varitemindata[i]){_____
if(item.toString()==='text'){_______
createEl.appendChild(document.createTextNode(data[i][item]));________ontinue;___________
_f(item.toString()==='html'){_______
createEl.innerHTML=item,data[i][item];_______
continue;_____
}_____
_reateEl.setAttribute(item,data[i][item]);_______
//****将填充好的node插入文档片段****___
fragment.appendChild(createEl);___
//****将文档片段统一插入目标容器****_
targetEl.appendChild(fragment);_
//显示容器,完成数据填充_
targetEl.style.display=
targetEl_display;
}
//使用
varwrap=document.querySelectorAll('.wrap')[0];
vardata=[_
_name:'xujaing',text:'选景',title:'xuanfij'},_
{name:'xujaing',text:'选景',title:'xuanfij'},_
{name:'xujaing',text:'选景',title:'xuanfij'}];
appendDataToEl({_
target:wrap,_
createEl:'div',
_ata:data
});
上面的优化方法使用了文档片段:_蔽颐前盐牡灯尾迦氲浇诘阒惺保导噬媳惶砑拥闹皇歉闷蔚淖咏诘悖皇瞧伪旧怼?梢允沟_om操作更有效率。
②.缓存布局信息
//缓存布局信息
letcurrent=el.offsetLeft;
current++;
el.style.left=current+'px'
if(current>300){_
stop();
}
④.慎用:hover
如果有大量元素使用:hover,那么会降低相应速度,CPU升高
⑤.使用事件委托(通过事件冒泡实现)来减少事件处理器的数量,减少内存和处理时间
functiondelegation(e,selector,callback){_
e=e||window.event;_
vartarget=e.target||e.srcElement;
_if(target.nodeName!==selector||
target.className!==selector||target.id!==selector){___
return;
_}_
if(typeofe.preventDefault==='function'){__
_.preventDefault();___
e.stopPropagation();
}else{___
e.returnValue=false;
e.cancelBubble=true;_
}
__allback()}
四.算法和流程控制
1.循环中减少属性查找并反转(可以提升50%-60%的性能)
//for循环
for(vari=item.length;i--){_
process(item[i]);
}
//while循环
varj=item.length;
while(j--){_
process(item[i]);
}
2.使用Duff装置来优化循环(该方法在后面的文章中会详细介绍)
3.基于函数的迭代(比基于循环的迭代慢)
items.forEach(function(value,index,array){__rocess(value);})
4.通常情况下switch总比if-else快,但是不是最佳方案
五.字符串和正则表达式
1.除了IE外,其他浏览器会尝试为表达式左侧的字符串分配更多的内存,然后简单的将第二个字符串拷贝到他的末尾,如果在一个循环中,基础字符串位于最左侧,就可以避免重复拷贝一个逐渐变大的基础字符串。2.使用[sS]来匹配任意字符串3.去除尾部空白的常用做法:
if(!String.prototype.trim){_
String.prototype.trim=function(){___
returnthis.replace(/^s+/,'').replace(/ss*$/,'')_
}
}
六.快速响应的用户界面
1.浏览器的UI线程:用于执行javascript和更新用户界面的进程。
2.在windows系统中定时器分辨率为15毫秒,因此设置小于15毫秒将会使IE锁定,延时的最小值建议为25ms.
3.用延时数组分割耗时任务:
functionmultistep(steps,args,callback){_
vartasks=steps.concat();
__etTimeout(function(){___
vartask=tasks.shift();___
task.apply(null,args||[]);_//调用Apply参数必须是数组
___
if(tasks.length>0){_____
setTimeout(arguments.callee,25);
___else{_____
_allback();___
__
},25);
}
4.记录代码运行时间批处理任务:
functiontimeProcessArray(items,process,callback){_
vartodo=item.concat();__etTimeout(function(){___
varstart=+newDate();
__o{_____
_rocess(todo.shift());___
}while(todo.length>0&&(+newDate()-start<50));
____f(todo.length>0){_____
_etTimeout(arguments.callee,25);
___else{____
_allback(items);_
}_
_,25)
}
5.使用WebWorker:它引入了一个接口,能使代码运行且不占用浏览器UI线程的时间。一个Worker由如下部分组成:
①一个navigator对象,包括app