1. 程式人生 > 其它 >js遞迴遍歷樹結構_前端效能優化之遞迴

js遞迴遍歷樹結構_前端效能優化之遞迴

技術標籤:js遞迴遍歷樹結構

這次分享,我們主要來看看前端效能優化方面的內容。

前端效能優化,可以從很多方面進行,下面是效能優化的冰山一角的內容。

  1. JS、CSS壓縮合並(減少HTTP請求)
  2. 將CSS放在頭部、JavaScript檔案放在底部
  3. 第三方庫打包成vendor,單獨載入
  4. 資源按需載入(import(), require.ensure())
  5. 利用事件代理(事件冒泡)
  6. 減少DOM的重排與重繪(diff演算法)
  7. 動畫開啟GPU加速(will-change, transform)
  8. 圖片優化(圖片延遲載入,降低圖片質量等)
  9. 利用瀏覽器快取,強快取或者協商快取(webpack splitChunks,固定hash)
  10. 使用HTTP2(解析速度快、多路複用、頭部壓縮)
  11. 靜態資源使用CDN
  12. ....

效能優化是個值得研究和深入挖掘的一塊領域,不但可以在極大的提高使用者體驗,在這方面的技能提升也可以更上一層樓,成為“磚家”。

這裡抖下機靈。最近股市基金一片大好,賺錢效應明顯,坐在家裡吹空調(科技)、吃火鍋、喝小酒(消費)、看病(醫療)就可以賺到不少買菜錢。

4cae225301e6cb1e9833f5170ccb101b.png

d46a9e592d32fa055aefbccda13ec7b6.png

單單從科技上來說噢,假如我們全面5G、全面新基建的情況下,5G相較於4G,資料傳輸速率遠遠高於4G,基本按照目前的情況來說,app、h5的訪問速度,理論上,都可以實現毫秒開。

按照這種情況來說,給各位前輩提一個抖機靈的問題,我們還需要搞這些什麼前端效能優化嗎..?

迴歸正題,迴歸正題。現階段我們還是需要優化的。但是在這次分享中,不講上述的優化哈,這裡主要說說程式碼層面遞迴的優化。

7ad385a0d48c60450d15479d06226f98.png

351b30fd99b80826afecc7d7cb6d4883.png

這次分享,主要從以下幾個點進行

  • 遞迴wiki定義
  • 遞迴帶來的問題
    • 爆棧
    • 迴圈引用
  • 遞迴優化
    • 尾呼叫優化
    • 快取代理
    • 遞迴轉遍歷
  • 參考資料

遞迴wiki定義

1623e6d4ae7d9688f2d2c41e8325372d.png


遞迴(英語:Recursion),又譯為遞迴,在數學與電腦科學中,是指在函式的定義中使用函式自身的方法。通俗的點說呢,就是 方法自己呼叫自己。
遞迴思想就是:把問題分解成規模更小,但和原問題有著相同解法的問題。在實際開發過程中,遞迴有非常多的運用,比如深複製、斐波那契數列、階乘、求和等等。
使用遞迴,需要滿足一下條件,否則會導致爆棧。

  • 自己呼叫自己
  • 邊界條件

比如如下程式碼。用途不同,但是共性是一樣的。

// 階乘
function factorial (n: number): number {
    if (n == 1) return n;
    return n * factorial(n - 1)
}
console.log(factorial(5)) // 5 * 4 * 3 * 2 * 1 = 120
// 斐波那契數列
function fibonacci (n: number): (number | Function) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(5)) // 1 1 2 3 5

遞迴帶來的問題

遞迴帶來的問題,是災難性的

19cdb945a99de6455379fe333cc338e5.png

首先,遞迴時沒有寫邊界條件。這種情況會觸發瀏覽器(Chrome)最大呼叫棧的錯誤RangeError: Maximum call stack size exceeded,導致badjs。也就是說上面所說的爆棧。Chrome(83.0.4103.116)支援最大呼叫棧為15673。如下測試程式碼。

let 

407e6a99562b51b6465d2c7c5c563db7.png

其次,遞迴沒有爆棧,但阻塞js載入。這裡阻塞js載入並沒有觸發RangeError錯誤,但是由於呼叫次數過多,導致程式碼執行被拖慢。看看如下程式碼。

const 

7d0475027dc2467c9e73c980df1c3b90.png

上面只是涉及到數學問題,我們回到業務場景看看。

最後,深拷貝迴圈引用導致爆棧。假設有一個cloneTest函式,接受一個物件作為引數,返回一個物件。如下程式碼。

function 

8d63a6a2158fd39bf145ce0a968f50b3.png

遞迴優化

以上簡單的說了下函式遞迴引發的一些問題。如如遞迴爆棧、阻塞js執行等,進而引起badjs激增,嚴重影響使用者體驗。

針對種種情況,我們是有辦法來解決的。

尾呼叫優化

尾呼叫,是指函式內部的最後一個動作是函式呼叫。該呼叫的返回值,直接返回給函式。尾呼叫不需要儲存當前詞法作用域(外層函式的呼叫棧內容)資訊,直接用內層函式的呼叫棧,取代外層函式的呼叫棧。

// 尾呼叫

上面程式碼中,情況一是呼叫函式g之後,還有賦值操作,所以不屬於尾呼叫,即使語義完全一樣。情況二也屬於呼叫後還有操作,即使寫在一行內。情況三等同於下面的程式碼。

function 

尾呼叫和非尾呼叫的差別在於,它們的函式上下文不同。

在實際開發過程中,尾呼叫的實現,可以將詞法作用域用到的引數,都放到函式引數中。 如下程式碼。

// 純遞迴

540cbcd97fa69999767bd22443509b6b.png

bd66a35edffc38989dbae04024837481.png

效率極大極大的提升。

5a739322eea2e7b9e0ee0da14df875db.png

快取代理

還是以斐波那契數列舉 。如果每次遞迴都依賴上一次的結果,那麼就可以利用代理模式中的快取代理,來實現效率上的提升。

// 快取代理

8928cdb389d118d785f0a6ac314a4faa.png

遞迴轉遍歷

遞迴轉遍歷,可以避免呼叫棧過多導致爆棧的問題,方法的實現主要是利用了棧結構。

function 

以上。

參考文章

  • 函式的擴充套件
  • 深拷貝的終極探索(99%的人都不知道)