前端性能优化方法(前端性能优化)
你们好,最近小活发现有诸多的小伙伴们对于前端性能优化方法,前端性能优化这个问题都颇为感兴趣的,今天小活为大家梳理了下,一起往下看看吧。
1、 最佳实践1:使用DocumentFragments或innerHTML代替复杂的元素注入。
2、 DOM操作在浏览器上是要纳税的。虽然性能提升在浏览器,但是DOM非常慢。如果你没有注意到,你可能会注意到浏览器运行速度非常慢。这就是为什么减少创建集中DOM节点的数量并快速注入它们如此重要。现在假设我们的页面中有一个ul元素,调用AJAX获取JSON列表,然后使用javascript更新元素内容。通常,程序员会这样写:
3、 var list=document . query selector(' ul ');
4、 Ajax result . items . foreach(function(item){
5、 //创建li元素
6、 var Li=document . createelement(' Li ');
7、 Li . innerhtml=item . text;
8、 //Li元素的一般操作,如添加类、改变属性、添加事件监听等。
9、 //快速将li元素注入父ul。
10、 list.apppendChild(李);
11、 });
12、 上面的代码其实是一种错误的写法。在每个列表上移植带有DOM操作的ul元素非常慢。如果您真的想使用document.createElement并将对象视为节点,那么出于性能原因,您应该使用DocumentFragement。
13、 DocumentFragement是一组子节点的“虚拟存储”,它没有父标签。在我们的例子中,可以将DocumentFragement看作一个不可见的ul元素,它将您的子节点保持在DOM之外,直到它们被注入到DOM中。然后,可以用DocumentFragment优化原始代码:
14、 var frag=document . createdocumentfragment();
15、 Ajax result . items . foreach(function(item){
16、 //创建li元素
17、 var Li=document . createelement(' Li ');
18、 Li . innerhtml=item . text;
19、 //Li元素的一般操作
20、 //比如添加类、更改属性、添加事件监听器、添加子节点等。
21、 //将li元素添加到片段中
22、 frag.appendChild(李);
23、 });
24、 //最后通过DocumentFragment将所有列表对象注入DOM。
25、 document.querySelector('ul ')。appendChild(frag);
26、 将子元素追加到DocumentFragment,然后将此DocumentFragment添加到父列表。这一系列操作只是一个DOM操作,所以比集中式注入要快很多。
27、 如果不需要将列表对象作为节点来操作,更好的方法是用字符串构建html内容:
28、 var html str=“”;
29、 Ajax result . items . foreach(function(item){
30、 //生成包含HTML页面内容的字符串。
31、 html str=' Li ' item . text '/Li '
32、 });
33、 //通过innerHTML设置ul内容。
34、 document.querySelector('ul ')。innerHTML=htmlStr
35、 DOM操作只有一次,代码量比DocumentFragment少。无论如何,这两种方法都比在每次迭代中向DOM注入元素更有效。
36、 最佳实践2:高频执行事件/方法的防抖
37、 通常开发者会在有用户交互的地方添加事件,往往这样的事件会被频繁触发。想象一下一个窗口的resize事件或者一个元素的onmouseover事件——当它们被触发时,执行速度非常快,而且会被触发很多次。如果你的回调太重,可能会把浏览器杀了。这就是为什么我们要引入防抖。
38、 防抖可以限制一个方法在一定时间内可以执行的次数。以下代码是一个防抖示例:
39、 //来自UnderscoreJS的实用程序框架
40、 功能去抖(func,wait,immediate) {
41、 var超时;
42、 返回函数(){
43、 var context=this,args=arguments
44、 var later=function() {
45、 超时=空;
46、 如果(!immediate) func.apply(context,args);
47、 };
48、 var callNow=immediate!超时;
49、 clearTimeout(超时);
50、 timeout=setTimeout(稍后,等待);
51、 if (callNow) func.apply(context,args);
52、 };
53、 }
54、 //添加resize的回调函数,但只允许每300毫秒执行一次。
55、 window . addevent listener(' resize 'debounce(function(event) {
56、 //在此编写调整大小的过程
57、 }, 300));
58、 去抖方法返回一个方法来包装你的回调函数并限制它的执行频率。使用这种防抖方法,可以让你的频繁回调方法不干扰用户的浏览器!
59、 最佳实践3:网络存储的静态缓存和不必要内容的优化
60、 webStorage的API曾经是Cookie API的重大改进,已经被开发者使用了很多年。这个API是合理的,有更大的存储容量,更加健全合理。一种策略是使用会话存储来存储不必要的、更静态的内容,比如侧边栏中的HTML内容、从Ajax加载的文章内容或其他各种片段,我们只想请求一次。我们可以使用JavaScript编写一段代码,并使用Web存储来简化这些内容的加载:
61、 define(function() {
62、 var cache obj=window . session storage | | {
63、 getItem:函数(键){
64、 归还这个[钥匙];
65、 },
66、 setItem:函数(键,值){
67、 这个[键]=值;
68、 }
69、 };
70、 返回{
71、 get:函数(键){
72、 返回this . is fresh(key);
73、 },
74、 设置:功能(键、值、分钟){
75、 var expDate=new Date();
76、 exp date . set minutes(exp date . get minutes()(minutes | | 0));
77、 尝试{
78、 cacheObj.setItem(key,JSON.stringify({
79、 价值:价值,
80、 expires: expDate.getTime()
81、 }));
82、 }
83、 catch(e) { }
84、 },
85、 isFresh:函数(键){
86、 //返回值或返回false
87、 var项目;
88、 尝试{
89、 item=JSON . parse(cache obj . getitem(key));
90、 }
91、 catch(e) {}
92、 如果(!item)返回false
93、 //日期算法
94、 返回新日期()。getTime() item.expires?false:item . value;
95、 }
96、 }
97、 });
98、 该工具提供了一个基本的get和set方法,与isFresh方法一样,可以确保存储的数据不会过期。调用方法也很简单:
99、 要求(['存储'],函数(存储){
100、 var content=storage . get(' sidebar content ');
101、 如果(!内容){
102、 //执行AJAX请求来获取侧栏内容
103、 //.然后将返回的内容存储一个小时
104、 storage.set('sidebarContent 'Content,60);
105、 }
106、 });
107、 现在,相同的内容不会被重复请求,您的应用程序将更有效地运行。花点时间看看你网站的设计,挑出那些不会改变,但会被不断请求的内容。您可以使用Web存储工具来提高网站的性能。
108、 最佳实践4:使用异步加载和延迟加载依赖项。
109、 RequireJS迎来了异步加载和AMD格式的巨大浪潮。XMLHttpRequest(这个对象可以调用AJAX)使得资源的异步加载流行起来,它允许非阻塞的资源加载,并使onload启动更快,允许页面内容无需刷新页面即可加载。我使用的异步加载器是约翰汉恩的curl。Curl loader是一个基本的异步加载器,可以配置,有很好的插件。以下是curl的简短代码:
110、 //基本用法:加载一些AMD格式的模块。
111、 curl(['social '' dom'],function(social,dom) {
112、 dom.setElementContent('social-container 'social . load widgets());
113、 });
114、 //使用Google Analytics定义一个模块,非AMD格式。
115、 定义(['js!//google-analytics.com/ga.js'],function() {
116、 //返回一个简单的自定义Google Analytics控制器
117、 返回{
118、 trackPageView:函数(href) {
119、 _gaq.push(['_trackPageview 'URL]);
120、 },
121、 trackEvent: function(eventName,href) {
122、 _gaq.push(['_trackEvent '' Interactions 'eventName ' 'href || window.location,true]);
123、 }
124、 };
125、 });
126、 //加载一个没有回调方法的非AMD js文件。
127、 curl(['js!//some site . com/widgets . js ']);
128、 //将JavaScript和CSS文件作为模块加载。
129、 curl(['js!libs/prism/prism.js '' css!libs/prism/prism.css'],function() {
130、 prism . highlight all();
131、 });
132、 //加载AJAX请求的URL。
133、 curl(['text!sidebar.php '' storage '' dom'],function(content,storage,dom) {
134、 storage.set('侧边栏'内容,60);
135、 dom.setElementContent('侧边栏’,内容);
136、 });
137、 你可能已经知道异步加载可以大大提高展示速度,但是我在这里要明确一点,你要用异步加载!你用了之后就能看出区别,更重要的是你的用户也能看出区别。
138、 当您可以根据页面内容延迟加载依赖项时,您就可以实现异步加载的好处。例如,你可以将Twitter、脸书和Google Plus加载到一个叫做social的CSS样式的div元素中。“加载前检查是否需要”的策略可以为我的用户节省几千字节的不必要的加载。
139、 最佳实践5:使用Array.prototype.join而不是字符串串联。
140、 优化客户端有一个很简单的方法,就是用Array.prototype.join代替原来的基本字符连接的写法。在上面的“最佳实践1”中,我在代码中使用了基本的字符连接:
141、 html str=' Li ' item . text '/Li '
142、 但是在下面的代码中,我使用了优化:
143、 var items=[];
144、 Ajax result . items . foreach(function(item){
145、 //生成一个字符串
146、 items.push('li 'item.text,'/Li ');
147、 });
148、 //通过innerHTML设置列表内容。
149、 document.querySelector('ul ')。innerHTML=items . join(' ');
150、 也许你需要花一点时间来看看这个数组是干什么用的,但是所有用户都从这个优化中受益了。
151、 最佳实践6:尽可能使用CSS动画。
152、 网站设计对美学特性和可配置元素动画的巨大需求,使得一些JavaScript类库,如jQuery和MooTools等被广泛使用。虽然现在浏览器支持CSS的变换和keyframe制作的动画,很多人还是用JavaScript来制作动画效果,但其实使用CSS动画比JavaScript驱动的动画效率更高。CSS动画也需要更少的代码。很多CSS动画都是GPU处理的,所以动画本身非常流畅。当然,您可以使用以下简单的CSS来强制您的硬件加速:我的动画{
153、 动画:someAnimation 1s
154、 transform: translate3d(0,0,0);/*强制硬件加速*/
155、 }
156、 transform:transform(0,0,0)发送对硬件加速的调用,而不影响其他动画。当不支持CSS动画时(IE8及以下版本的浏览器),可以引入JavaScript动画逻辑:
157、 !-[如果低于IE8版本]
158、 script src=' http://code . jquery . com/jquery-1 . 9 . 1 . min . js '/script
159、 script src='/js/ie-animations . js '/script
160、 ![endif] -
161、 在上面的例子中,ie动画。JS文件必须包含你自定义的jQuery代码,在早期IE不支持CSS动画的情况下,用来代替CSS动画完成动画效果。完美动画由CSS动画优化,全局动画效果由JavaScript支持。
162、 最佳实践7:使用事件委托
163、 想象一下,如果您有一个无序列表,其中有一堆li元素,每个li元素在被单击时都会触发一个行为。这时候你一般会给每个元素添加一个事件监听器,但是如果这个元素或者你添加了监听器的对象会被频繁的移除和添加怎么办?此时,您需要在移除和添加元素的同时处理事件侦听器的移除和添加。这时候就需要引入事件委托了。事件委托是在父元素上添加一个事件侦听器,而不是在每个子元素上添加一个事件侦听器。当事件被触发时,event.target将评估是否需要实施相应的措施。这里我们举一个简单的例子:
164、 //获取元素并添加事件侦听。
165、 document . query selector(' # parent-list ')。addEventListener('click '函数(e) {
166、 //e.target是被点击的元素!
167、 //如果是列表元素
168、 if(e . target e . target . tagname==' LI '){
169、 //我们找到了这个元素,对它的操作可以写在这里。
170、 }
171、 });
172、 上面的例子非常简单。当事件发生时,它不会轮询父节点来查找匹配的元素或选择器,也不支持基于选择器的查询(比如使用类名或id来查询)。所有JavaScript框架都提供委托选择器匹配。重点是,避免为每个元素加载事件侦听器,而是向父元素添加一个事件侦听器。这样大大提高了效率,减少了很多维护!
173、 最佳实践8:使用数据URI代替图片SRC
174、 提高页面大小的效率不仅取决于向导或压缩代码的使用,还取决于给定页面的请求数量。减少请求可以让你的网站加载更快,减少页面请求的方法之一就是用数据URI替换图片的src属性:
175、 !-旧的写作方式-
176、 img src='/images/logo . png ' alt='前端性能优化最佳实践'/
177、 !-使用数据URI的书写方法-
178、 img src=' data:image/JPEG;' base64,/9j/4 aaqskzjrgabagazabkaad/7 aarhvja 3 kaaqaaaaaaaapaaa/4 adkfkb 2 jlagtaaaaaaaf/baiqabgqebauebgkgbqyjcwggbggldaokwokdbamdawqda 4 pea 8 odbmtfbqtxwbgxschx 8 FH x8 FH x8 FH x8 FH x8 FH x8 FH x8 FH x8 FH 8 FH 8 FH 8 FH 8 FH . '/
179、 -例如:http://davidwalsh.name/demo/data-uri-php.php-
180、 当然,页面大小会增加(如果您的服务器使用适当的gzip内容,这种增加会非常小),但您减少了潜在的请求,并减少了过程中服务器请求的数量。目前大部分浏览器都支持数据URI,CSS中的背景骨骼片段也可以使用数据URI,所以这种策略现在可以在应用层面广泛使用。
181、 最佳实践9:使用媒体查询加载指定大小的背景图片。
182、 在CSS @supports得到广泛支持之前,CSS媒体查询的使用已经接近于对CSS中编写逻辑的控制。我们经常使用CSS media query根据设备(通常是根据屏幕宽度)调整CSS属性,比如根据不同的屏幕宽度设置不同的元素宽度或者浮动位置。那么我们为什么不这样改变背景图片呢?
183、 /*默认为加载桌面应用程序的图片*/。some element { background-image:URL(sunset . jpg);}
184、 @媒体专用屏幕和(最大宽度:1024像素){。some element { background-image:URL(sunset-small . jpg);}
185、 }
186、 上面的代码片段是为手机设备或者类似的移动设备加载一个小图片,特别是需要特别小的图片的时候(比如图片的大小几乎看不见)。
187、 最佳实践10:使用索引对象
188、 在本文中,我们将讨论使用索引对象检索代替遍历数组来提高遍历速度。AJAX和JSON最常见的一个用例是接收一个包含一组对象的数组,然后根据给定的值从这个数组中搜索对象。让我们看一个简单的例子。在本例中,您从用户处接收一个数组,然后您可以根据username的值搜索用户对象:
189、 函数getUser(desiredUsername) {
190、 var search result=Ajax result . users . filter(function(user){
191、 return user . username==desiredUsername;
192、 });
193、 返回searchResult.length?search result[0]:false;
194、 }
195、 //根据用户名获取用户
196、 var David Walsh=getUser(' David Walsh ');
197、 //根据用户名获取另一个用户。
198、 var tech pro=getuser(' tech-pro ');
199、 上面的代码可以运行,但是不是很有效。当我们想要得到一个用户时,我们必须遍历一次数组。那么更好的方法是创建一个新对象,并为每个唯一值建立一个索引。在上面的例子中,使用用户名作为索引,这个数组对象可以写成:
200、 var user store={ };
201、 Ajax result . users . foreach(function(user){
202、 userStore[user.username]=用户;
203、 });
204、 现在当你想查找一个用户对象时,我们可以通过索引直接找到这个对象:
205、 var David Walsh=user store . David Walsh;
206、 var tech pro=user store[' tech-pro '];
207、 这种代码写起来更好更简单,按索引搜索比遍历整个数组更快。
208、 最佳实践11:控制DOM大小
209、 在本文中,我们将讨论如何控制DOM的大小来优化前端性能。众所周知DOM慢,而造成网站慢的罪魁祸首就是大量的DOM。想象一下,如果您有一个包含数千个节点的DOM。试想一下,使用querySelectorAll或者getElementByTagName,或者其他以DOM为中心的搜索方法来搜索一个节点,即使使用内置的方法,也会是一个非常费力的过程。你知道,额外的DOM节点会降低其他实用程序的速度。
210、 我见过一种情况,DOM的大小悄悄增加了。它位于一个AJAX网站中,该网站将所有页面存储在DOM中。当通过AJAX加载新页面时,旧页面将存储在一个隐藏的DOM节点中。DOM的速度将会大大降低,尤其是当页面被动态加载时。所以你需要一个更好的方法。
211、 在这种情况下,当页面通过AJAX加载,上一页存储在客户端时,最好的方法是通过字符串HTML存储内容(从DOM中删除内容),然后使用事件委托来避免特定的元素事件。同时,在客户机上缓存内容时,可以避免大量的DOM生成。
212、 控制DOM大小的常用技术包括:
213、 使用:before和:after伪元素。
214、 延迟加载和呈现内容
215、 使用事件委托,更容易将节点转换为字符串存储。
216、 简单地说:尽量让你的DOM小一些。
217、 最佳实践12:在繁重的执行任务中使用Web Workers
218、 在本文中,我们将介绍WebWorker,这是一种可以将繁重的操作转移到独立进程的方法。前段时间在流行的浏览器中引入了Webworkers,但似乎并没有得到广泛的应用。Web Workers的主要作用是执行一般浏览器执行范围之外的重方法。它不会访问DOM,所以必须传入方法中涉及的节点。
219、 以下是webworker的示例代码:
220、 /*使用Web Worker */
221、 //启动工作进程
222、 var Worker=new Worker('/path/to/web/Worker/resource . js ');
223、 worker . addevent listener(' message 'function(event) {
224、 //我们从web worker那里获得信息!
225、 });
226、 //指导Web Worker工作!
227、 worker . postmessage({ cmd:' processImageData 'data:convertimagetotauri(my image)});
228、 /* resource.js是webworker */
229、 self.addEventListener('message 'function(event) {
230、 var data=event.data
231、 开关(data.cmd) {
232、 案例“流程”:
233、 返回processImageData(data . imagedata);
234、 });
235、 函数processImageData(imageData) {
236、 //对图像进行操作
237、 //比如改成灰度。
238、 返回newImageData
239、 }
240、 上面的代码是一个简单的例子,教你如何使用Web Worker在其他进程中做一些繁重的工作。它需要做的是将一张图片从正常颜色变成灰度。因为这是一个相当繁重的过程,所以您可以将这个过程提交给Web Worker,这样您的浏览器的负载就不会很重。数据通过消息事件返回。
241、 你可以仔细阅读下面MDN上WebWorker的用法。也许你的网站上有一些功能可以移到其他独立的进程中。
242、 最佳实践13:链接CSS,避免使用@import。
243、 有时候@import太好用了,很难抵挡它的诱惑,但是为了减少令人抓狂的请求,你必须拒绝它!最常见的用法是在“主”CSS文件中,没有内容,只有@import规则。有时,多个@import规则通常会导致事件嵌套:
244、 //主CSS文件(main.css)
245、 @ import ' reset.css
246、 @ import ' structure.css
247、 @ import ' tutorials.css
248、 @ import ' contact.css
249、 //然后在tutorials.css文件中,@import继续。
250、 @ import ' document.css
251、 @ import ' syntax-highlight er . CSS '
252、 当我们编写这样的CSS文件时,文件中有两个额外的链接,这会降低页面加载速度。SASS可以读取@import语句,将CSS内容链接到一个文件中,减少冗余请求,控制CSS文件大小。
253、 最佳实践14:在CSS文件中包含多种媒体类型。
254、 在上面的第13个最佳实践中,我们说过多个CSS文件可以通过@import规则合并在一起。但是很多程序员不知道的是,多个CSS媒体类型也可以合并成一个文件。
255、 /*以下所有内容都写在一个CSS文件中*/
256、 @媒体屏幕{
257、 /*所有默认的结构设计和元素样式都写在这里*/
258、 }
259、 @媒体印刷{
260、 /*调整打印样式*/
261、 }
262、 @媒体专用屏幕和(最大宽度:1024像素){
263、 /*使用ipad或手机时的风格设置*/
264、 }
265、 对于文件大小,什么时候必须合并媒体,或者什么时候必须单独设置媒体,没有硬性规定,但是我会建议合并所有媒体,除非一个媒体的比例远大于其他媒体。对于客户端和服务器来说,少一个请求会容易得多,并且在大多数情况下,补充媒体类型比主屏幕媒体类型小得多。
以上就是前端性能优化这篇文章的一些介绍,希望对大家有所帮助。
免责声明:本文由用户上传,如有侵权请联系删除!
猜你喜欢
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
最新文章
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03
- 01-03