首頁 >web前端 >html教學 >關於HTML5中效能優化的詳解

關於HTML5中效能優化的詳解

黄舟
黄舟原創
2017-07-27 09:56:101788瀏覽

HTML5效能最佳化

--減少重繪

        在HTML頁面完成展現之後,動態改變頁面元素或調整CSS樣式都會造成瀏覽器重繪,效能的損耗直接取決於動態改變的範圍:如果只是改變一個元素的顏色之類的資訊則只會重繪該元素;而如果是增刪節點或調整節點位置則會引起其兄弟節點也一併重繪。

        減少重繪不是說不要重繪,而是要注意重繪範圍:①改動的DOM元素越深則影響越小,所以盡量深入節點改動;②對某些DOM樣式有多重變動盡量合併成一起修改。

以改變一個3499910bf9dac5ae3c52d5ede7383485標籤的背景色、寬度和顏色為例。


<a href="javascript:void(0);" id="example">传统的代码</a> 
<script> 
 var example = document.getElementById("example"); 
 example.ondblclick = function() { 
 example.style.backgroundColor = "red"; 
 example.style.width = "200px"; 
 example.style.color = "white"; 
 } 
</script>


以上會執行3次重繪,而透過CSS取代javascript多次執行則只進行一次重繪。

 


<style> 
 .dblClick { 
 width: 200px; 
 background: red; 
 color: white; 
 } 
</style> 
<a href="javascript:;" id="example">CSS优化的代码</a> 
<script> 
 var example = document.getElementById("example"); 
 example.ondblclick = function() { 
 example.className = "dblClick"; 
 } 
</script>

避免腳本阻塞載入

        當瀏覽器在解析常規的script標籤時,它要等待script下載完畢,再解析執行,而後續的HTML程式碼只能等待。 CSS檔案引入要放在93f0f5c25f18dab9d176bd4f6de5d30e頭部,因為這是HTML渲染必備元素。為了避免阻塞加載,應把腳本放到文件的末尾,而CSS是需要放在頭部的!


<head>
<link rel="stylesheet" href="common.css">......<script src="example.js"></script>
</body>

--避免節點深層巢狀

        深層巢狀的節點在初始化建置時往往需要更多的記憶體佔用,並且在遍歷節點時也會更慢些,這與瀏覽器建立DOM文件的機制有關。瀏覽器會把整個HTML文件的結構儲存為DOM「樹」結構。當文件節點的巢狀層次越深,建構的DOM樹層次也會越深。

如下程式碼,完全能夠去掉e388a4556c0f65e1904146cc1a846bee或45a2772a6b6107b401db3c9b82c049c2其中一個標籤。


<p>
  <span>
    <label>嵌套</label>
  </span>
</p>


頁快取

        通常不設定快取的情況下,每次重新整理頁面都會重新讀取伺服器的文件,而如果設定快取之後,所有文件都可以從本地取得,這樣明顯極大地提高了頁面效率。

我們可以透過設定頁面頭的expires來定義頁面過期時間,將過期時間定久一點就達到了「永久」快取。


<meta http-equiv="expires" content="Sunday 26 October 2099 01:00 GMT" />

 當然,如果你的專案程式碼有變更,因為客戶端快取了文件就不會得到最新的文件,勢必造成顯示錯誤。基於這個問題的解決方案就是給連結文件加一個時間戳,如果時間戳有變化,瀏覽器會認為是新文件,就會向伺服器請求最新文件。


<script src="example2014-6-17.js">
</script>//如果是JSP,可以用EL表达式来取时间戳信息,这样管理更加方便
<script src="example${your time param}.js">
</script>//或者这样的写法更优秀:
<script src="example.js?time=2014-6-7"></script>
<script src="example.js?time=${your time param}"></script>


壓縮合併檔案

        所有涉及請求資料的檔案盡量做壓縮,例如Javascript檔案、css文件及圖片文件,特別是圖片文件,如果沒有高清晰要求,完全可以壓縮後再使用。

        數量少體積大的檔案比數量多體積小的檔案載入速度快,所以有時候可以考慮將多個js檔案、多個css檔案合併在一起。

除此之外減少HTML文件大小還可以採取以下幾種方法:

①刪掉HTM文件對執行結果無影響的空格空行與註解

# ②避免Table佈局

③使用HTML5

--HTML+CSS3+Javascript各司其職

        讓三元素各司其職才能做出高效能的網頁:HTML是頁面之本也是內容之源,有了它就能跟CSS和Javascript交互;CSS3可以說是展現大師,而且日漸強大的CSS能代替Javascript做很多動態的事情如漸變、行動等動態效果;Javascript是動態資料之王,舊瀏覽器依靠js來完成動態效果展現,但現在的CSS也能完成js的工作,所以盡量將工作交給css,這樣會獲得更好的效能。 (這個說得有點大)

--圖片合併實現CSS Sprites

        圖片合併其實就是將網頁中一些背景圖片整合到一張圖片檔案中,再利用CSS 的“background-image”,“background- repeat”,“background-position”的組合進行背景定位,background-position可以用數字能精確的定位出背景圖片的位置。

        一個頁面要用到多個圖標,完全可以將多個圖標合併成一個圖,然後只需發送一次圖片請求,透過css定位分割圖標即可。

--避免使用Iframe

        使用iframe并不会增加同域名下的并行下载数,浏览器对同域名的连接总是共享浏览器级别的连接池,在页面加载过程中iframe元素还会阻塞父文档onload事件的触发。并且iframe是html标签中最消耗资源的标签,它的开销比p、SCRIPT、STYLE等DOM高1~2个数量级。

避免onload事件被阻塞,可使用JavaScript动态的加载iframe元素或动态设置iframe的src属性(但其仅在高级浏览器IE9及以上有效)。


<iframe id="if"></iframe>
document.getElementById("if").setAttribute("src","url");

--多域名请求

        一般来说,浏览器对于相同域名的图片,最多用2-4个线程并行下载(不同浏览器的并发下载数是不同的)。而相同域名的其他图片,则要等到其他图片下载完后才会开始下载。

        有时候,图片数据太多,一些公司的解决方法是将图片数据分到多个域名的服务器上,这在一方面是将服务器的请求压力分到多个硬件服务器上,另一方面,是利用了浏览器的特性。(大家可以去新浪、腾讯门户网站查看,这些大型站点同一页面加载的图片可能由多个站点提供)

        注:一个HTML请求的域名也不要太多(2~3个差不多),多了可能造成不同服务器连接时间差异,反而影响速度。

--避免空链接属性

        如624a480c6387e73c22b4f60ddcc0f14e8fb0647cc270c6c60ce1679670afa6fc这样的设置方式是非常不可取的,即使链接为空,在旧的浏览器也会以固定步骤发送请求信息。

        另外9dba6f1f949f5e07bed667bf670fd9c45db79b134e9f6b82c0b36e0489ee08ed也不可取,最好的方式是在链接中加一个空的js代码af60cb7cd5eb3467eaa609628cdd0ba95db79b134e9f6b82c0b36e0489ee08ed

--使用图像的BASE64编码

        base64是一串字符串,他可以代表一个图片的所有信息,也就是可以通过09522e18412c10a262484dd8ba0b09ee(S表示一串base64码)来显示图片,这种方式不需要再向服务器发送请求,完全由浏览器解析成图片。

        目前高级浏览器都支持此功能,但要注意两点:①低版本浏览器(如IE7)不支持;②base64字符串长度随图片的大小及复杂度成正比,base64也像URL一样,也有超出长度的情况(在IE8下很常见)。所以要根据情况来使用。

--显式设置图片的宽高

        如果HTML里的图片没有指定尺寸(宽和高),或者代码描述的尺寸与实际图片的尺寸不符时,浏览器则要在图片下载完成后再“回溯”该图片并重新显示,这会消耗额外时间。


<iframe id="if"></iframe>
document.getElementById("if").setAttribute("src","url");

--显式指定文档字符集

        如果浏览器不能获知页面的编码字符集,一般都会在执行脚本和渲染页面前,把字节流缓存,然后再搜索可进行解析的字符集,或以默认的字符集来解析页面代码,这会导致消耗不必要的时间。


<iframe id="if"></iframe>
document.getElementById("if").setAttribute("src","url");

--渐进式增强设计

        渐进式增强设计的通俗解释就是:首先写一段满足所有浏览器的基本样式,再在后面针对不同高级浏览器编写更漂亮的样式

        如下代码,所有浏览器都支持background-color: #2067f5;满足了浏览器基本现实需求,而后面的background-image: -webkit-gradient等则为不同高级浏览器使用,只要浏览器识别就能执行这段代码(不识别,CSS也不会报错只会直接忽略)。


<p class="someClass"></p> 
.someClass 
{ width: 100px; 
 height: 100px; 
 background-color: #2067f5; 
 background-image: -webkit-gradient(linear, left top, left bottom, from(#2067f5), 
to(#154096)); 
 background-image: -webkit-linear-gradient(top, #2067f5, #154096); 
 background-image: -moz-linear-gradient(top, #2067f5, #154096); 
 background-image: -ms-linear-gradient(top, #2067f5, #154096); 
 background-image: -o-linear-gradient(top, #2067f5, #154096); 
 background-image: linear-gradient(to bottom, #2067f5, #154096); 
}

--懒加载与预加载

        预加载和懒加载,是一种改善用户体验的策略,它实际上并不能提高程序性能,但是却可以明显改善用户体验或减轻服务器压力。

        预加载表示当前用户在请求到需要的数据之后,页面自动预加载下一次用户可能要看的数据,这样用户下一次操作的时候就立刻呈现,依次类推。

        懒加载表示用户请求什么再显示什么,如果一个请求要响应的时间非常长,就不推荐懒加载。

--Flush机制

        當一個頁面非常大,內容非常多,可以採用flush的形式分部分返回給頁面,這樣能告訴用戶我正在工作,顯示一部分內容比白屏等很長時間要好得多。在Java Web技術中,實作Flush非常簡單,只要呼叫 HttpServletResponse.getWriter輸出流的flush方法,就可以將已經完成載入的內容寫回給客戶端。

        此方式只適用於回傳資料特別多、請求時間特別長的情況,常規資料還是用正常的即時全部回傳最佳。這種實作方式實際上會增加瀏覽器渲染時間和使用者整體等待時間,但從使用者體驗上會更加優秀。

  • 效能之伺服器最佳化

--CDN機制

        所謂的CDN,就是一種內容分發網絡,它採用智慧路由和流量管理技術,及時發現能夠給訪客提供最快回應的加速節點,並將訪客的請求導向到該加速節點,由該加速節點提供內容服務。

        通俗點說,你在成都(瀏覽器)購買了北京賣家(伺服器)的產品,北京賣家透過快遞(CDN服務)寄送包裹,從北京到成都可以走路、坐汽車、火車或飛機,而採用CND的快遞會選擇飛機直達,因為這種寄送方式最快。

當然使用CDN有兩個注意事項:

1、CDN加速服務很貴,如果你覺得你的網站值得加速,可以選擇購買;

#2、 CDN不適合區域性網站,例如你的網站只有某一個片區訪問或區域網路訪問,因為區域網路本來就很近,無需CDN加速。

--HTTP協定的合理使用

        瀏覽器快取帶來的效能提升已經眾人皆知了,而許多人卻不知道瀏覽器的緩存過期時間、快取刪除、什麼頁面可以快取等,都可以由我們程式設計師來控制,只要您熟悉HTTP協議,就可以輕鬆的控制瀏覽器。

延伸閱讀:深入理解HTTP協定

--動靜分離

        所謂的動靜分離,就是將Web應用程式中靜態且動態的內容分別放在不同的Web伺服器上,有針對性的處理動態和靜態內容,從而達到效能的提升。我們知道如果一個HTML有多個網域請求資料檔會提高

Tomcat伺服器在處理靜態和並發問題上比較弱,所以事先動靜分離的方式一般會用Apache+Tomcat、Nginx+Tomcat等。

        以Apache+Tomcat為例,其操作機制是:頁面請求先給Apache,然後Apache分析請求資訊是靜態還是動態,靜態則本機處理,動態則交給Tomcat處理。

        這其實是負載平衡的雛形,這樣的實作不用讓開發人員做任何特殊開發,一個ad9fd35425518ae8aa6a6d6c2800cfa8交給伺服器即可,至於這個檔案是從Apache還是從Tomcat取得,開發人員完全無需關注。

--HTTP持久連結

        持久連結(Keep-Alive)也稱為長連接,它是一種TCP的連接方式,連接會被瀏覽器和伺服器所緩存,下次連接同一伺服器時,快取的連線被重新使用。 HTTP無狀態性表示了它不屬於長連接,但HTTP/1.1提供了對長連接的支援(不過這必須依賴瀏覽器和伺服器雙方均支援長連接功能才行),最常見的HTTP長連接範例是「斷點下載」。

        瀏覽器在請求的頭部添加Connection:Keep-Alive,以此告訴服務器“我支持長連接,你支持的話就和我建立長連接吧”,而倘若服務器的確支持長連接,那麼就在響應頭部添加“Connection:Keep-Alive”,從而告訴瀏覽器“我的確也支持,那我們建立長連接吧”。伺服器也可以透過Keep-Alive:timeout=..., max=...的頭部告訴瀏覽器長連線失效時間。

        配置長連接通常是要伺服器支援設置,有測試數據顯示,使用長連接和不使用長連接的性能對比,對於Tomcat配置的maxKeepAliveRequests為50來說,效率竟然提升了將近5倍。

--GZIP壓縮技術

        HTTP協定支援GZIP的壓縮格式,當伺服器傳回的HTML資訊標頭中包含Content-Encoding:gzip,它告訴瀏覽器,這個回應的回傳資料已經壓縮成GZIP格式,瀏覽器取得資料後要進行解壓縮操作,一定程度上減輕了伺服器傳輸資料的壓力。

        很多服务器已经支持通过配置来自动将HTML信息压缩成GZIP,比如tomcat、又比如很火的Nginx。如果无法配置服务器级别的GZIP压缩机制,可以改为程序压缩。

 // 监视对 gzipCategory 文件夹的请求
 @WebFilter(urlPatterns = { "/gzipCategory/*" }) 
 public class GZIPFilter implements Filter { 

 @Override 
 public void doFilter(ServletRequest request, ServletResponse response, 
 FilterChain chain) throws IOException, ServletException { 
 String parameter = request.getParameter("gzip"); 
 // 判断是否包含了 Accept-Encoding 请求头部
 HttpServletRequest s = (HttpServletRequest)request; 
 String header = s.getHeader("Accept-Encoding"); 
 //"1".equals(parameter) 只是为了控制,如果传入 gzip=1,才执行压缩,目的是测试用
 if ("1".equals(parameter) && header != null && header.toLowerCase().contains("gzip")) { 
 HttpServletResponse resp = (HttpServletResponse) response; 
 final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 

 HttpServletResponseWrapper hsrw = new HttpServletResponseWrapper( 
 resp) { 

 @Override 
 public PrintWriter getWriter() throws IOException { 
 return new PrintWriter(new OutputStreamWriter(buffer, 
 getCharacterEncoding())); 
 } 

 @Override 
 public ServletOutputStream getOutputStream() throws IOException { 
 return new ServletOutputStream() { 

 @Override 
 public void write(int b) throws IOException { 
 buffer.write(b); 
 } 
 }; 
 } 

 }; 

 chain.doFilter(request, hsrw); 
 byte[] gzipData = gzip(buffer.toByteArray()); 
 resp.addHeader("Content-Encoding", "gzip"); 
 resp.setContentLength(gzipData.length); 
 ServletOutputStream output = response.getOutputStream(); 
 output.write(gzipData); 
 output.flush(); 
 } else { 
 chain.doFilter(request, response); 
 } 
 } 
 // 用 GZIP 压缩字节数组
 private byte[] gzip(byte[] data) { 
 ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240); 
 GZIPOutputStream output = null; 
 try { 
 output = new GZIPOutputStream(byteOutput); 
 output.write(data); 
 } catch (IOException e) { 
 } finally { 
 try { 
 output.close(); 
 } catch (IOException e) { 
 } 
 } 
 return byteOutput.toByteArray(); 
 } 
……
 }
  • 总结

        细节决定成败,系统慢是由一个又一个不良的小细节造成的,所以开发初期做好充足的准备,开发中认真负责、不偷工减料,维护期更要注重代码质量,这样才能让我们的系统稳定高效。

        个人觉得一个产品的新版本质量可以从核心js文件看出来:如果核心js文件大小比上一版本大太多,明显在性能上就会有问题,我们要争做像谷歌、亚马逊这样优秀的团队--能够在功能升级的同时减小核心js文件大小。

 

以上是關於HTML5中效能優化的詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn