DNS 解析也是須要時間的,能夠經過預解析的方式來預先得到域名所對應的 IP。javascript
<link rel="dns-prefetch" href="//yuchengkai.cn">
複製代碼
緩存對於前端性能優化來講是個很重要的點,良好的緩存策略能夠下降資源的重複加載提升網頁的總體加載速度。html
一般瀏覽器緩存策略分爲兩種:強緩存和協商緩存。前端
實現強緩存能夠經過兩種響應頭實現:Expires
和 Cache-Control
。強緩存表示在緩存期間不須要請求,state code
爲 200java
Expires: Wed, 22 Oct 2018 08:41:00 GMT
複製代碼
Expires
是 HTTP / 1.0 的產物,表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT
後過時,須要再次請求。而且 Expires
受限於本地時間,若是修改了本地時間,可能會形成緩存失效。面試
Cache-control: max-age=30
複製代碼
Cache-Control
出現於 HTTP / 1.1,優先級高於 Expires
。該屬性表示資源會在 30 秒後過時,須要再次請求。算法
若是緩存過時了,咱們就可使用協商緩存來解決問題。協商緩存須要請求,若是緩存有效會返回 304。跨域
協商緩存須要客戶端和服務端共同實現,和強緩存同樣,也有兩種實現方式。瀏覽器
Last-Modified
表示本地文件最後修改日期,If-Modified-Since
會將 Last-Modified
的值發送給服務器,詢問服務器在該日期後資源是否有更新,有更新的話就會將新的資源發送回來。緩存
可是若是在本地打開緩存文件,就會形成 Last-Modified
被修改,因此在 HTTP / 1.1 出現了 ETag
。性能優化
ETag
相似於文件指紋,If-None-Match
會將當前 ETag
發送給服務器,詢問該資源 ETag
是否變更,有變更的話就將新的資源發送回來。而且 ETag
優先級比 Last-Modified
高。
對於大部分的場景均可以使用強緩存配合協商緩存解決,可是在一些特殊的地方可能須要選擇特殊的緩存策略
Cache-control: no-store
,表示該資源不須要緩存Cache-Control: no-cache
並配合 ETag
使用,表示該資源已被緩存,可是每次都會發送請求詢問資源是否更新。Cache-Control: max-age=31536000
並配合策略緩存使用,而後對文件進行指紋處理,一旦文件名變更就會馬上下載新的文件。由於瀏覽器會有併發請求限制,在 HTTP / 1.1 時代,每一個請求都須要創建和斷開,消耗了好幾個 RTT 時間,而且因爲 TCP 慢啓動的緣由,加載體積大的文件會須要更多的時間。
在 HTTP / 2.0 中引入了多路複用,可以讓多個請求使用同一個 TCP 連接,極大的加快了網頁的加載速度。而且還支持 Header 壓縮,進一步的減小了請求的數據大小。
更詳細的內容你能夠查看 該小節
在開發中,可能會遇到這樣的狀況。有些資源不須要立刻用到,可是但願儘早獲取,這時候就可使用預加載。
預加載實際上是聲明式的 fetch
,強制瀏覽器請求資源,而且不會阻塞 onload
事件,可使用如下代碼開啓預加載
<link rel="preload" href="http://example.com">
複製代碼
預加載能夠必定程度上下降首屏的加載時間,由於能夠將一些不影響首屏但重要的文件延後加載,惟一缺點就是兼容性很差。
能夠經過預渲染將下載的文件預先在後臺渲染,可使用如下代碼開啓預渲染
<link rel="prerender" href="http://example.com">
複製代碼
預渲染雖然能夠提升頁面的加載速度,可是要確保該頁面百分百會被用戶在以後打開,不然就白白浪費資源去渲染
對於代碼層面的優化,你能夠查閱瀏覽器系列中的 相關內容。
懶執行就是將某些邏輯延遲到使用時再計算。該技術能夠用於首屏優化,對於某些耗時邏輯並不須要在首屏就使用的,就可使用懶執行。懶執行須要喚醒,通常能夠經過定時器或者事件的調用來喚醒。
懶加載就是將不關鍵的資源延後加載。
懶加載的原理就是隻加載自定義區域(一般是可視區域,但也能夠是即將進入可視區域)內須要加載的東西。對於圖片來講,先設置圖片標籤的 src
屬性爲一張佔位圖,將真實的圖片資源放入一個自定義屬性中,當進入自定義區域時,就將自定義屬性替換爲 src
屬性,這樣圖片就會去下載資源,實現了圖片懶加載。
懶加載不只能夠用於圖片,也可使用在別的資源上。好比進入可視區域纔開始播放視頻等等。
對於一張 100 * 100 像素的圖片來講,圖像上有 10000 個像素點,若是每一個像素的值是 RGBA 存儲的話,那麼也就是說每一個像素有 4 個通道,每一個通道 1 個字節(8 位 = 1個字節),因此該圖片大小大概爲 39KB(10000 * 1 * 4 / 1024)。
可是在實際項目中,一張圖片可能並不須要使用那麼多顏色去顯示,咱們能夠經過減小每一個像素的調色板來相應縮小圖片的大小。
瞭解瞭如何計算圖片大小的知識,那麼對於如何優化圖片,想必你們已經有 2 個思路了:
head
中script
標籤放在 body
底部,由於 JS 文件執行會阻塞渲染。固然也能夠把 script
標籤放在任意位置而後加上 defer
,表示該文件會並行下載,可是會放到 HTML 解析完成後順序執行。對於沒有任何依賴的 JS 文件能夠加上 async
,表示加載和渲染後續文檔元素的過程將和 JS 文件的加載與執行並行無序進行。Webworker
。Webworker
可讓咱們另開一個線程執行腳本而不影響渲染。靜態資源儘可能使用 CDN 加載,因爲瀏覽器對於單個域名有併發請求上限,能夠考慮使用多個 CDN 域名。對於 CDN 加載靜態資源須要注意 CDN 域名要與主站不一樣,不然每次請求都會帶上主站的 Cookie。
對於代碼運行錯誤,一般的辦法是使用 window.onerror
攔截報錯。該方法能攔截到大部分的詳細報錯信息,可是也有例外
Script error.
對於這種狀況咱們須要給 script
標籤添加 crossorigin
屬性arguments.callee.caller
來作棧遞歸對於異步代碼來講,可使用 catch
的方式捕獲錯誤。好比 Promise
能夠直接使用 catch
函數,async await
可使用 try catch
可是要注意線上運行的代碼都是壓縮過的,須要在打包時生成 sourceMap 文件便於 debug。
對於捕獲的錯誤須要上傳給服務器,一般能夠經過 img
標籤的 src
發起一個請求。
如何渲染幾萬條數據並不卡住界面
這道題考察瞭如何在不卡住頁面的狀況下渲染數據,也就是說不能一次性將幾萬條都渲染出來,而應該一次渲染部分 DOM,那麼就能夠經過 requestAnimationFrame
來每 16 ms 刷新一次。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>控件</ul>
<script> setTimeout(() => { // 插入十萬條數據 const total = 100000 // 一次插入 20 條,若是以爲性能很差就減小 const once = 20 // 渲染數據總共須要幾回 const loopCount = total / once let countOfRender = 0 let ul = document.querySelector("ul"); function add() { // 優化性能,插入不會形成迴流 const fragment = document.createDocumentFragment(); for (let i = 0; i < once; i++) { const li = document.createElement("li"); li.innerText = Math.floor(Math.random() * total); fragment.appendChild(li); } ul.appendChild(fragment); countOfRender += 1; loop(); } function loop() { if (countOfRender < loopCount) { window.requestAnimationFrame(add); } } loop(); }, 0); </script>
</body>
</html>
複製代碼