--減少重繪
在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中文網其他相關文章!