前端性能优化方案(前端提高页面性能优化)
你们好,最近小活发现有诸多的小伙伴们对于前端性能优化面试题,前端性能优化这个问题都颇为感兴趣的,今天小活为大家梳理了下,一起往下看看吧。

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元素常规操作,如添加类、更改属性attribute、添加事件监控等。
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、 //比如添加类、更改属性attribute、添加事件监控、添加子节点等。
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的回调函数,但只允许每300ms执行一次。
55、 window . addevent listener(' resize 'debounce(function(event) {
56、 //在此编写调整大小的过程
57、 }, 300));
58、 去抖方法返回一个方法来包装你的回调函数并限制它的执行频率。使用这种防抖方法,可以让你的频繁回调方法不妨碍用户的浏览器!
59、 最佳实践3:静态缓存和网络存储的非必要内容优化
60、 存储的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、 //使用非AMD格式的Google Analytics定义一个模块
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元素中。“加载前检查是否需要”的策略可以为我的用户节省几KB的不必要加载。
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、 Tanform: 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='/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 8 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属性(通常是根据屏幕宽度调整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、 我见过一种情况,在一个AJAX网站中,DOM的大小悄悄地增加,所有的页面都存储在DOM中。当通过AJAX加载新页面时,旧页面将存储在隐藏的DOM节点中。DOM的速度将会大大降低,尤其是当页面被动态加载时。所以你需要一个更好的方法。
211、 在这种情况下,当页面通过AJAX加载,上一页存储在客户端时,最好的方法是通过String HTML存储内容(从DOM中移除内容),然后使用事件委托来避免特定的元素事件。同时,在客户端缓存内容时,可以避免大量的DOM。
212、 控制DOM大小的常用技术包括:
213、 使用:before和:after伪元素。
214、 延迟加载和呈现内容
215、 使用事件委托,更容易将节点转换为字符串并存储它们。
216、 底线:尽量让你的DOM尽可能小。
217、 最佳实践12:使用Web Workers进行繁重的执行
218、 在本文中,我们将介绍Web Workder,这是一种可以将繁重的操作转移到独立进程的方法。Workers在前段时间被引入到流行的浏览器中,但它似乎并没有被广泛使用。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、 //我们从网络工作者那里获得信息!
225、 });
226、 //指导网络工作者工作!
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,这样您的浏览器就不会负载过重。通过datamessage事件返回。
241、 你可以仔细阅读下面关于Web Workder使用的MDN。也许你的网站上有一些功能可以转移到其他独立的进程中去执行。
242、 最佳实践13:链接CSS并避免使用@import
243、 有时候,@import太好用了,你很难抵挡它的诱惑,但是为了减少令人抓狂的请求,你不得不拒绝它!最常见的用法是在只有@import规则的“主”CSS文件中。有时,多个@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、 至于文件大小,CSS中并没有硬性规定媒体必须合并或单独设置,但我会建议合并所有媒体,除非其中一个媒体的比例远大于其他媒体。少一个请求对客户机和服务器来说都会容易得多,而且在大多数情况下,附加的媒体类型相对来说要比主屏幕媒体类型小得多。
以上就是前端性能优化这篇文章的一些介绍,希望能帮助到大家。
扫描二维码推送至手机访问。
版权声明:文章内容摘自网络,如果无意之中侵犯了您的版权,请联系本站,本站将在3个工作日内删除。谢谢!
