中国白嫩的18sex少妇hd,色网av,欧美黄色三级,一本色道久久88综合日韩精品

前端與seo有什么關聯嗎

  最近工作中一個項目在運行時有一些性能問題,為此我看了很多與性能優化相關的內容,下面做個簡單的分享。

  前端性能優化,這包括 CSS/JS 性能優化、網絡性能優化等等內容,這方面的內容 《高性能網站建設指南》、《高性能網站建設進階指南》、《高性能JavaScript》 等等書都做了很多講解,強烈推薦閱讀。(這些書單參見本文結尾)

  下面的內容,上面提到的書中大都包含了,因此可以考慮轉而去讀這些書,做一個完完全全的了解,對于本文,也就不要再讀下去了。

  如果你堅持看到了這里,那就來談談我遇到的一些前端性能問題,并聊聊解決方案。

  1 優先優化對性能影響大的部分

  當應用有了性能問題后,不要一股腦扎到代碼中去,首先要想想那部分對性能影響最大。優先優化那些對性能影響大的部分,可以起到立桿見影的效果。

  使用 Chrome DevTools ,可以很快地找到導致性能變差的最主要因素,關于 Chrome DevTools 的使用強烈推薦閱讀 Google Developers 上面的系列教程 - Chrome DevTools。

  另外在對代碼進行優化的時候,也首先要關注那些存在循環或者高頻調用的地方。有的時候我們可能不知道某個地方是否會高頻執行,比如某些事件的回調。這個時候可以使用 console.count 來對執行次數進行統計。當這部分高頻執行的代碼已經足夠優化的時候,就要考慮是否能夠減少執行次數。比如一個時間復雜度為 O(n*n*n) 的算法,再怎么優化也不如將其變為 O(n*n) 來的快。

  2 對高頻觸發的事件進行節流或消抖

  對于 Scroll 和 Touchmove 這類事件,永遠不要低估了它們的執行頻率,處理這類事件的時候可以考慮是否要給它們添加一個節流或者消抖過的回調。節流和消抖,可能其他人不這么翻譯,其實也就是 debounce 和throttle 這兩個函數。

  debounce 和 throttle 是兩個相似(但不相同)的用于控制函數在某段事件內的執行頻率的技術。你可以在 underscore 或者 lodash 中找到這兩個函數。

  2.1 使用 debounce 進行消抖

  多次連續的調用,最終實際上只會調用一次。想象自己在電梯里面,門將要關上,這個時候另外一個人來了,取消了關門的操作,過了一會兒門又要關上,又來了一個人,再次取消了關門的操作。電梯會一直延遲關門的操作,直到某段時間里沒人再來。

  所以 debounce 適合用在比如對用戶輸入內容進行校驗的這種場景下,多次觸發只需要響應最后一次觸發就好了。

  2.2 使用 throttle 進行節流

  將頻繁調用的函數限定在一個給定的調用頻率內。它保證某個函數頻率再高,也只能在給定的事件內調用一次。比如在滾動的時候要檢查當前滾動的位置,來顯示或隱藏回到頂部按鈕,這個時候可以使用 throttle 來將滾動回調函數限定在每 300ms 執行一次。

  需要提到的是,這兩個函數常常被誤用,且很多時候當事人并沒有意識到自己誤用了。我曾經用錯過,也見過別人用錯。這兩個函數都接受一個函數作為參數,然后返回一個節流/去抖后的函數,下面第二種用法才是正確的用法:

  // 錯誤的用法,每次事件觸發都得到一個新的函數

  $(window).on('scroll', function() {

  _.throttle(doSomething, 300);

  });

  // 正確的用法,將節流后的函數作為回調

  $(window).on('scroll', _.throttle(doSomething, 200));

  3 JavaScript 很快,DOM 很慢

  JavaScript 如今已經很快了,真正慢的是 DOM。因此避免使用一些不易讀但據說能提高速度的寫法。不久前,

  一位朋友對我說使用 ‘+’ 號將字符串轉為數字比使用 parseInt 快。對此我并沒有懷疑,因為直覺上 parseInt 進行了函數調用,很可能會慢一些,我們一起在 node v6.3.0 上進行了一些驗證,結果的確如我們所預計的那樣,但是差別有多大呢,進行了 5 億次迭代,使用 + 號的方法僅僅快了2秒。雖然快了兩秒,但實際中將字符轉為數字的操作可能只會進行幾次,因此這樣的做法根本沒有意義,它只會讓代碼變得更難讀。

  plus: 1694.392ms

  parseInt: 3661.403ms

  真正慢的是 DOM,DOM 對外提供了 API,而 JavaScript 可以調用這些 API,它們兩者就像是使用一座橋梁相連,每次過橋都要被收取大量費用,因此應該盡量讓減少過橋的次數。

  3.1 為什么 DOM 很慢

  談到這里需要對瀏覽器利用 HTML/CSS/JavaScript 等資源呈現出精彩的頁面的過程進行簡單說明。瀏覽器在收到 HTML 文檔之后會對文檔進行解析開始構建 DOM (Document Object Model) 樹,進而在文檔中發現樣式表,開始解析 CSS 來構建 CSSOM(CSS Object Model)樹,這兩者都構建完成后,開始構建渲染樹。整個過程如下:

  渲染樹的構建過程

  在每次修改了 DOM 或者其樣式之后都要進行 DOM樹的構建,CSSOM 的重新計算,進而得到新的渲染樹。瀏覽器會利用新的渲染樹對頁面進行重排和重繪,以及圖層的合并。通常瀏覽器會批量進行重排和重繪,以提高性能。但當我們試圖通過 JavaScript 獲取某個節點的尺寸信息的時候,為了獲得當前真實的信息,瀏覽器會立刻進行一次重排。

  3.2 避免強制性同步布局

  在 JavaScript 中讀取到的布局信息都是上一幀的信息,如果在 JavaScript 中修改了頁面的布局,比如給某個元素添加了一個類,然后再讀取布局信息。這個時候為了獲得真實的布局信息,瀏覽器需要強制性對頁面進行布局。因此應該避免這樣做。

  3.3 批量操作 DOM

  在必須要進行頻繁的 DOM 操作時,可以使用 fastdom 這樣的工具,它的思路是將對頁面的讀取和改寫放進隊列,在頁面重繪的時候批量執行,先進行讀取后改寫。因為如果將讀取與改寫交織在一起可能引起多次頁面的重排。而利用 fastdom 就可以避免這樣的情況發生。

  雖然有了 fastdom 這樣的工具,但有的時候還是不能從根本上解決問題,比如我最近遇到的一個情況,與頁面簡單的一次交互(輕輕滾動頁面)就執行了幾千次 DOM 操作,這個時候核心要解決的是減少 DOM 操作的次數。這個時候就要從代碼層面考慮,看看是否有不必要的讀取。

  另外一些關于高效操作 DOM 的方法,可以參見《高性能JavaScript》相關章節,也可以先參考一下我的讀書筆記 《高性能JavaScript》 (https://github.com/wy-ei/notebook/issues/34 )

  4 優化渲染性能

  瀏覽器通常每秒更新頁面 60 次,每一幀的時間就是 16.6ms,為了能讓瀏覽器保持 60幀 的幀率,為了讓動畫看起來流暢,需要保證幀率達到 60fps,因此每一幀的邏輯需要在 16.6ms 內完成。

  每一幀實際上都包含下列步驟:

  因此,通常 JavaScript 的執行時間不能超過 10ms。

  JavaScript:改變元素樣式,添加元素到 DOM 中等等

  Style:元素的類或者style改變了,這個時候需要重新計算元素的樣式

  Layout:需要重新計算元素的具體尺寸

  Paint:將元素的繪制的圖層上

  Composite:合并多個圖層

  當然也不是說每一幀都會進行這些操作。當你的 JavaScript 改變了某個 layout 屬性,比如元素的 width 和height 或者 top 等等,瀏覽器就會重新計算布局,并對整個頁面進行重排。

  如果修改了 background、color 這樣的僅僅會讓頁面重繪的屬性,這不會影響頁面的布局,瀏覽器會跳過計算布局(layout)的過程,只進行重繪(paint)。

  如果修改了一個不需要計算布局也不需要重繪的屬性,那就只會進行圖層的合并,這是代價最小的修改。從https://csstriggers.com/ 上你可以知道修改那些樣式屬性會觸發(Layout,Paint,Composite)中的那些操作。

  4.1 將漸變或者會動畫元素放到單獨的繪制層中

  繪制并非在一個單獨的畫布上進行的,而是多層。因此將那些會變動的元素提升至單獨的圖層,可以讓他的改變影響到的元素更少。

  可以使用 CSS 中的 will-change: transform; 或者 transform: translateZ(0); 這樣來將元素提升至單獨的圖層中。

  使用 Chrome DevTools 來審查圖層

  在調試的時候你可以在 Chrome DevTools 的 timeline 面板來觀察繪制圖層。當然也不是說圖層越多越好,因為新增加一個圖層可能會耗費額外的內存。且新增加一個圖層的目的是為了避免某個元素的變動影響其他元素。

  4.2 降低繪制復雜度

  某些屬性的重繪相對而言更加復雜,比如 filter、box-shadow 等濾鏡或漸變效果。因此不要濫用這類效果。

  5 優化 JavaScript 的執行

  下面提到的 JavaScript 優化,并不是說如何讓 JavaScript 執行的更快,而是如何讓 JavaScript 更高效地與 DOM 配合。

  5.1 使用 requestAnimationFrame 來更新頁面

  我們希望在每一幀剛開始的時候對頁面進行更改,目前只有使用 requestAnimationFrame 能夠保證這一點。使用setTimeout 或者 setInterval 來觸發更新頁面的函數,該函數可能在一幀的中間或者結束的時間點上調用,進而導致該幀后面需要進行的事情沒有完成,引發丟幀。

  使用 setTimeout 可能導致丟幀

  requestAnimationFrame 會將任務安排在頁面重繪之前,這保證動畫能有足夠的時間來執行 JavaScript 。

  5.2 使用 Web Worker 來處理復雜的計算

  JavaScript 是在單線程的,并且可能會一直這樣,因此 JavaScript 在執行復雜計算的時候很可能會阻塞線程,導致頁面假死。但 Web Worker 的出現,以另外一種方式給了我們多線程的能力,可以將復雜計算放在 worker 中進行,當計算完成后,以 postMessage 的形式將結果傳回來。

  對于單個函數,因為 Web Worker 接受一個腳本的 url 作為參數,使用 URL.createObjectURL 方法,我們可以將一個函數的內容轉換為 url,利用它創建一個 worker。

  var workerContent=`

  self.onmessage=function(evt){

  // ...

  // 在這里進行復雜計算

  var result=complexFunc();

  // 將結果傳回

  self.postMessage(result);

  };`

  // 得到 url

  var blob=new Blob([workerContent]);

  var url=window.URL.createObjectURL(blob);

  // 創建 worker

  var worker=new Worker(url);

  5.3 使用 transform 和 opacity 來完成動畫

  如今只有對這兩個屬性的修改不需要經歷 layout 和 paint 過程。

  6 優化 CSS

  CSS 選擇器在匹配的時候是由右至左進行的,因此最后一個選擇器常被稱為關鍵選擇器,因為最后一個選擇越特殊,需要進行匹配的次數越少。要千萬避免使用 *(通用選擇器)作為關鍵選擇器。因為它能匹配到所有元素,進而倒數第二個選擇器還會和所有元素進行一次匹配。這導致效率很低下。

  div p * {}

  另外 first-child 這類偽類選擇器也不夠特殊,也要避免將它們作為關鍵選擇器。關鍵選擇器越特殊,瀏覽器就能用較少的匹配次數找到待匹配元素,選擇器性能也就越好。

  還有一個老生常談的注意事項,不要使用太多的選擇器。如果還有同學很悲劇地要兼容低版本 IE,要避免使用 CSS 表達式,它的性能很差,詳細內容可參見我之前記錄的一篇筆記 《高性能網站建設指南》筆記(https://github.com/wy-ei/notebook/issues/15 )

  7 合理處理腳本和樣式表

  如今有了 requirejs,webpack 等工具,可能很少會在頁面中加載很多 JavaScript/CSS 代碼了。盡管如此,還是有必要談談如何合理處理腳本和樣式表。

  大多數人已經知道通常要把 JavaScript 放在文檔底部,把 CSS 放在文檔頂部。為什么呢?因為 JavaScript 會阻塞頁面的解析,而外部樣式表會阻塞頁面的呈現和 JavaScript 的執行。

  7.1 CSS阻塞渲染

  通常情況下 CSS 被認為是阻塞渲染的資源,在CSSOM 構建完成之前,頁面不會被渲染,放在頂部讓樣式表能夠盡早開始加載。但如果把引入樣式表的 link 放在文檔底部,頁面雖然能立刻呈現出來,但是頁面加載出來的時候會是沒有樣式的,是混亂的。當后來樣式表加載進來后,頁面會立即進行重繪,這也就是通常所說的閃爍了。

  7.2 JavaScript 阻塞文檔解析

  當在 HTML 文檔中遇到 script 標簽后控制權將交給 JavaScript,在 JavaScript 下載并執行完成之前,都不會解析 HTML。因此如果將 JavaScript 放在文檔頂部,恰好這個時候 JavaScript 腳本加載的特別慢,用戶將會等待很長一段時間,這段個時候 HTML 文檔還沒有解析到 body 部分,頁面會是空白的。

  另外常常被忽略的事實是:在瀏覽器沒有下載并解析完成使用 link 引入的 CSS 文件之前,JavaScript 是不會執行的,因為 JavaScript 中可能需要讀取樣式,而此時樣式表還沒有加載回來,因此瀏覽器不會執行 JavaScript。可以給 JavaScript 加上 async 標記,表示 JavaScript 的執行不會讀取 DOM ,JavaScript 可以不被 CSS 阻塞,可以在空閑時間立刻執行。

  綜上所述,你更要保證 CSS 文件加載的足夠快。

收藏
0
有幫助
0
沒幫助
0