網路有一項著名的8秒原則。當使用者造訪Web網頁時,如果時間超過8秒就會感到不耐煩,如果載入需要太長時間,他們就會放棄造訪。大部分用戶希望網頁能在2秒內完成載入。事實上,載入時間每多1秒,你就會流失7%的用戶。 8秒並不是準確的8秒鐘,只是向網站開發者表明了載入時間的重要性。那我們要如何優化頁面效能,提高頁面載入速度呢?這是本文主要要探討的問題,然而效能優化是個綜合性問題,沒有標準答案,想要面面俱到羅列出來,並非易事。本文只專注於一些核心要點,以下是我總結效能優化常見的辦法:
主要包含這些面向:html壓縮、css 壓縮、js的壓縮和混亂和檔案合併。
資源壓縮可以從檔案中去掉多餘的字符,例如回車、空格。你在編輯器中寫程式碼的時候,會使用縮排和註釋,這些方法無疑會讓你的程式碼簡潔且易讀,但它們也會在文件中添加多餘的位元組。
html程式碼壓縮就是壓縮這些在文字檔案中有意義,但是在HTML中不顯示的字符,包括空格,製表符,換行符等,還有一些其他意義的字符,如HTML註釋也可以被壓縮。
如何進行html壓縮:
使用線上網站進行壓縮(開發過程中一般不用)
#nodejs 提供了html-minifier工具
後端範本引擎渲染壓縮
css程式碼壓縮簡單來說就是無效程式碼刪除和css語意合併
如何進行css壓縮:
使用線上網站進行壓縮(開發過程中一般不用)
使用html-minifier工具
#使用clean-css對css壓縮
js的壓縮和混亂主要包括以下幾部分:
#無效字元的刪除
剔除註解
#程式碼語意的縮減與最佳化
程式碼保護(程式碼邏輯變得混亂,降低程式碼的可讀性,這點很重要)
#如何進行js的壓縮和混亂
使用線上網站進行壓縮(開發過程中一般不用)
#使用html-minifier工具
使用uglifyjs2對js進行壓縮
其實css壓縮與js的壓縮和混亂比html壓縮收益大得多,同時css程式碼和js程式碼比html程式碼多很多,透過css壓縮和js壓縮帶來流量的減少,會非常明顯。所以對大公司來說,html壓縮可有可無,但css壓縮與js的壓縮和混亂必須要有!
#從上圖可以看出不合併要求有以下缺點:
檔案與檔案之間有插入的上行請求,增加了N-1個網路延遲
受丟包問題影響更嚴重
keep-alive方式可能會出現狀況,經過代理伺服器時可能會被斷開,也就是說不能一直保持keep-alive的狀態
壓縮合併css和js可以減少網站http請求的次數,但合併檔案可能會帶來問題:首屏渲染和快取失效問題。那該如何處理這問題呢? ----公共庫合併和不同頁面的合併。
如何進行檔案合併
使用線上網站進行檔案合併
使用nodejs實作文件合併(gulp、fis3)
非同步載入的三種方式-async和defer、動態腳本建立
① async方式
<script></script>
② defer方式
如果是多个脚本,该方法可以确保所有设置了defer属性的脚本按顺序执行
如果脚本不会改变文档的内容,可将defer属性加入到script标签中,以便加快处理文档的速度
③动态创建script标签
在还没定义defer和async前,异步加载的方式是动态创建script,通过window.onload方法确保页面加载完毕再将script标签插入到DOM中,具体代码如下:
function addScriptTag(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function(){ addScriptTag("js/index.js"); }
1)defer是在HTML解析完之后才会执行,如果是多个,按照加载的顺序依次执行
2)async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
其中蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
对于web应用来说,缓存是提升页面性能同时减少服务器压力的利器。
1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码,并且size显示from disk cache或from memory cache;
Expires :response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。它的值为一个绝对时间的GMT格式的时间字符串, 比如Expires:Thu,21 Jan 2018 23:39:02 GMT
Cache-Control :这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示。当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。比如Cache-Control:max-age=300,
简单概括:其实这两者差别不大,区别就在于 Expires 是http1.0的产物,Cache-Control是http1.1的产物,两者同时存在的话,Cache-Control优先级高于Expires;在某些不支持HTTP1.1的环境下,Expires就会发挥用处。所以Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法。强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容较客户端是否已经发生了更新呢?此时我们需要协商缓存策略。
2.协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;另外协商缓存需要与cache-control共同使用。
①Last-Modified和If-Modified-Since:当第一次请求资源时,服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码,内容为空,这样就节省了传输数据量 。如果两个时间不一致,则服务器会发回该资源并返回200状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。一个304响应比一个静态资源通常小得多,这样就节省了网络带宽。
但last-modified 存在一些缺点:
Ⅰ.某些服务端不能获取精确的修改时间
Ⅱ.文件修改时间改了,但文件内容却没有变
既然根据文件修改时间来决定是否缓存尚有不足,能否可以直接根据文件内容是否修改来决定缓存策略?----ETag和If-None-Match
②ETag和If-None-Match:Etag是上一次載入資源時,伺服器傳回的response header,是對該資源的一種唯一標識,只要資源有變化,Etag就會重新生成。瀏覽器下次載入資源向伺服器發送請求時,會將上一次回傳的Etag值放到request header裡的If-None-Match裡,伺服器只需要比較客戶端傳來的If-None-Match跟自己伺服器上該資源的ETag是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。如果伺服器發現ETag匹配不上,那麼直接以常規GET 200回包形式將新的資源(當然也包括了新的ETag)發給客戶端;如果ETag是一致的,則直接返回304知會客戶端直接使用本地快取即可。
兩者之間對比:
首先在精確度上,Etag要優於Last-Modified#。 Last-Modified的時間單位是秒,如果某個文件在1秒內改變了多次,那麼他們的Last-Modified其實並沒有體現出來修改,但是Etag每次都會改變確保了精度;如果是負載平衡的伺服器,各伺服器產生的Last-Modified也有可能不一致。
第二在效能上,Etag要遜於Last-Modified,畢竟Last-Modified只需要記錄時間,而Etag需要伺服器透過演算法來計算出一個hash值。
第三在優先權上,伺服器校驗優先考慮Etag
強制快取優先於協商快取進行,若強制快取(Expires和Cache-Control)生效則直接使用緩存,若不生效則進行協商快取(Last-Modified / If-Modified-Since和Etag / If-None-Match),協商快取由伺服器決定是否使用緩存,若協商快取失效,那麼代表該請求的快取失效,重新取得請求結果,再存入瀏覽器快取中;生效則返回304,繼續使用快取。主要過程如下:
1.網址列訪問,連結跳轉是正常使用者行為,將會觸發瀏覽器快取機制;
2.F5刷新,瀏覽器會設定max-age=0,跳過強快取判斷,會進行協商快取判斷;
3.ctrl F5刷新,跳過強緩存和協商緩存,直接從伺服器拉取資源。
如果想了解更多快取機制,請猛戳深入理解瀏覽器的快取機制
大型Web應用對速度的追求並沒有止步於僅僅利用瀏覽器緩存,因為瀏覽器緩存始終只是為了提升二次訪問的速度,對於首次訪問的加速,我們需要從網絡層面進行優化,最常見的手段就是CDN(Content Delivery Network,內容傳遞網路)加速。 透過將靜態資源(例如javascript,css,圖片等等)快取到離用戶很近的相同網路營運商的CDN節點上,不但能提升用戶的存取速度,還能節省伺服器的頻寬消耗,降低負載。
其實這是CDN服務商在全國各省部署運算節點,CDN加速將網站的內容快取在網路邊緣,不同地區的使用者就會造訪到離自己最近的相同網路線路上的CDN節點,當請求達到CDN節點後,節點會判斷自己的內容快取是否有效,如果有效,則立即回應快取內容給用戶,從而加快回應速度。如果CDN節點的快取失效,它會根據服務配置去我們的內容來源伺服器取得最新的資源回應給用戶,並將內容快取下來以便回應給後續存取的用戶。 因此,一個地區內只要有一個用戶先加載資源,在CDN中建立了緩存,該地區的其他後續用戶都能因此而受益。
資源預先載入是另一個效能最佳化技術,我們可以使用該技術來預先告知瀏覽器某些資源可能在將來會被使用到。
透過 DNS 預解析來告訴瀏覽器未來我們可能會從某個特定的 URL 取得資源,當瀏覽器真正使用到該網域中的某個資源時就可以盡快完成 DNS 解析。例如,我們將來可從 example.com 取得圖片或音訊資源,那麼可以在文件頂部的
<link>
当我们从该 URL 请求一个资源时,就不再需要等待 DNS 的解析过程。该技术对使用第三方资源特别有用。通过简单的一行代码就可以告知那些兼容的浏览器进行 DNS 预解析,这意味着当浏览器真正请求该域中的某个资源时,DNS 的解析就已经完成了,从而节省了宝贵的时间。
另外需要注意的是,浏览器会对a标签的href自动启用DNS Prefetching,所以a标签里包含的域名不需要在head中手动设置link。但是在HTTPS下不起作用,需要meta来强制开启功能。这个限制的原因是防止窃听者根据DNS Prefetching推断显示在HTTPS页面中超链接的主机名。下面这句话作用是强制打开a标签域名解析
<meta>
以上是頁面效能優化的方法總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!