本文是學習《高性能javascript》(Nichols C. Zakes著)的一些總結,雖然書比較過期,裏面的知識點也有不少用不上了,可是畢竟是前人一步步探索過來的,記錄着javascript艱難的發展歷程,現在站在巨人的肩膀上,也許咱們也能發掘更好的javascript性能。javascript
第一章:加載和執行css
管理瀏覽器中的javascript代碼是個棘手的問題,由於代碼執行過程會阻塞瀏覽器的其餘進程,好比用戶界面繪製,每次遇到<script>標籤,頁面必須停下來等待代碼下載(如外部連接文件)並執行,而後繼續處理其餘部分,儘管如此,仍是有幾種方法能減小javascript對性能的影響。html
- <body/>閉合標籤以前,將全部的<script>標籤放到頁面底部,這能確保在腳本執行前頁面已經完成了渲染。
- 合併腳本,頁面中全部的<script>標籤越少,加載也就越快,響應也更迅速,不管外鏈文件仍是內部腳本都是如此。
- 有多種無阻塞的下載javascript的方法:
- 使用<script>標籤的defer屬性前端
- 使用動態建立的<script>元素來下載並執行代碼java
- 使用XHR對象下載javascript代碼並注入頁面中web
第二章:數據訪問ajax
在javascript中,數據存儲的位置會對代碼總體性能產生重大的影響。數據存儲共有4種方式:直接量、變量、數組項、對象成員,它們有不一樣的性能考慮。正則表達式
- 訪問直接量和局部量的速度最快,相反,訪問數組元素和對象成員相對較慢。
- 因爲局部變量存在於做用域鏈的起始位置,所以訪問局部變量比訪問跨做用域變量更快,變量在做用域鏈的位置越深,訪問所需的時間越長,因爲全局變量總處在做用域鏈的最末端,所以訪問速度也是最慢的。
- 避免使用with語句,由於它會改變運行期上下文做用域鏈。一樣,try-catch語句中的catch子句也有一樣的影響,所以要當心使用。
- 嵌套的對象成員會明顯影響性能,儘可能少用。
- 屬性或方法在原型鏈中的位置越深,訪問它的速度越慢。
- 一般來講,你能夠經過把它經常使用的對象成員、數組元素、跨域變量保存在局部變量中來改善javascript的性能,由於局部變量訪問速度更塊。
第三章:DOM編程算法
訪問和操做DOM是現代web應用的重要組成部分,但每次穿越鏈接ECMAScript和DOM兩個島嶼之間的橋樑,都會被收取「過橋費」,爲了減小DOM編程帶來的性能損失,請記住如下幾點:編程
- 最小化DOM訪問次數,儘量在javascript中斷處理。
- 若是須要屢次訪問某個DOM節點,請使用局部變量存儲它的引用。
- 當心處理HTML集合,由於它實時聯繫着底層文檔,把集合的長度緩存到一個變量中,並在迭代中使用它,若是須要常常操做集合,建議把它拷貝到一個數組中。
- 若是可能的話,使用速度更快的API,好比querySelectorAll()和firstElementChild().
- 要留意重繪和重排,批量修改樣式時,「離線」操做DOM樹,使用緩存,並減小訪問佈局次數。
- 動畫中使用絕對定位,使用拖放代理。
- 使用事件委託來減小事件處理器的數量。
第四章:算法和流程控制
如同其餘編程語言,代碼的寫法和算法會影響javascript的運行時間,與其餘語言不一樣的是,javascript可用資源有限,所以優化技術更爲重要。
- for、while和do-while循環性能特性類似,因此沒有一種循環類型明顯快於或慢於其餘類型。
- 避免使用for-in循環,除非你須要遍歷一個屬性數量未知的對象。
- 改善循環性能的最佳方式是減小每次迭代的運算量和減小循環迭代次數。
- 一般來講,switch總比if-else快,但並不老是最佳解決方案。
- 在判斷條件較多時,使用查找表比if-else和switch快。
- 瀏覽器的調用棧大小限制了遞歸算法在javascript中的應用,棧溢出錯誤會致使其餘代碼中斷運行。
- 若是你遇到棧溢出錯誤,可將方法改成迭代算法,或使用Memoization來避免重複計算。
- 運行的代碼數量越大,使用這些策略所帶來的性能提高也就越明顯。
第五章:字符串和正則表達式
密集的字符串操做和草率的編寫正則表達式可能產生嚴重的性能障礙,下面的方法助你避免常見的陷阱:
- 當鏈接數量巨大或尺寸巨大的字符串時,數組項鍊接是惟一在IE7及更早版本中性能合理的方法。
- 若是不考慮IE7及更早版本的性能,數組項鍊接是最慢的字符串鏈接方法之一,推薦使用簡單的+和+=操做符代替,避免沒必要要的中間字符串。
- 回溯既是正則表達式匹配功能的基本組成部分,也是正則表達式的低效之源。
- 回溯失控發生在正則表達式本應快速匹配的地方,但由於某些特殊的字符串匹配動做致使運行緩慢甚至瀏覽器崩潰。避免這個問題的辦法是:使相鄰的字元互斥,避免嵌套量詞對同一字符串的相同部分屢次匹配,經過重複利用向前查看的原子組去除沒必要要的回溯。
- 提升正則表達式效率的各類技術手段會有助於正則表達式更快的匹配,並在非匹配位置上花更少的時間。
- 正則表達式並不老是完成工做的最佳工具,尤爲當你只搜索字面字符串的時候。
- 儘管有許多方法能夠去除字符串的首尾空白,但使用兩個簡單的正則表達式(一個用來去頭部,一個用來去除尾部)來處理大量字符串內容能提供一個簡潔而跨瀏覽器的方法,從字符串末尾開始循環向前搜索第一個非空白字符,或者將此技術同正則表達式結合起來,會提供一個更好的替代方案,它不多受到字符串長度的影響。
第六章:快速響應的用戶界面
javascript和用戶界面更新在同一進程中運行,所以一次只能處理一件事情。這意味着當javascript代碼正在運行時,用戶界面不能響應輸入,反之亦然,高效的管理UI線程就是要確保javascript不能運行太長時間,以避免影響用戶體驗,最後請牢記如下幾點:
- 任何javascript任務都不該當執行超過100毫秒。過長的運行時間會致使UI更新出現明顯的延遲,從而對用戶體驗產生負面影響。
- javascript運行期間,瀏覽器響應用戶交互的行爲存在差別,不管如何,javascript長時間運行將致使用戶體驗變得混亂和脫節。
- 定時器可用來安排代碼延遲執行,它使得你能夠把長時間運行腳本分解成一系列的任務。
- Web workers是新版瀏覽器支持的特性,它容許你在UI 線程外部執行javascript代碼,從而避免鎖定UI。
- web應用越複雜,積極主動的管理UI線程就越重要,沒有什麼javascript代碼會重要到能夠影響用戶體驗的程度。
第七章:AJAX
高性能的ajax包括如下幾方面:瞭解你項目的具體需求,選擇正確的數據格式和與之匹配的傳輸技術。
做爲數據格式,純文本和html只適用於特定場合,但它們能夠節省客戶端的CPU週期,XML被普遍應用並且支持良好,可是它十分笨重且解析緩慢,JSON是輕量級的,解析速度塊(被視爲原生代碼而不是字符串),通用性與XML至關,字符分隔的自定義格式十分輕量,在解析大量數據集時很是快,但須要編寫額外的服務端構造程序,並在客戶端解析。
當從頁面當前所處的域下請求數據時,XHR提供了最完美的控制和靈活性,儘管它會把接收到的全部數據當成一個字符串,且這有可能下降解析速度。另外一方面,動態腳本注入容許跨域請求和本地執行javascript和JSON可是它的接口不那麼安全,並且還不能讀取頭信息或響應代碼。Multipart XHR能夠用來減小請求數,並處理一個響應中的各類文件類型,可是它不能緩存接收到的響應,當須要發送數據時,圖片信息是一種簡單而有效的方法,XHR還能夠用POST方法發送大量數據。
除了這些格式和傳輸技術,還有一些準則有助於加速你的AJAX.
- 減小請求數,可經過合併javascript和css文件,或使用MXHR.
- 縮短頁面的加載時間,頁面主要內容加載完成時,用ajax獲取那些次要的文件。
- 確保你的代碼不會輸出給用戶,並在服務端處理錯誤。
- 知道什麼時候使用成熟的ajax類庫,以及什麼時候編寫本身的底層ajax代碼。
第八章:編程實踐
javascript提出了一些獨一無二的性能挑戰,這與你組織代碼的方式有關。隨着web應用變得愈來愈高級,包含的javascript代碼愈來愈多,各類模式和反模式也逐漸出現,高效編程注意如下幾點:
- 經過避免使用eval()和Function()構造器來避免雙重求值帶來的性能消耗,一樣的,給setTimeout()和setInterval()傳遞函數而不是字符串做爲參數。
- 儘可能使用直接量建立對象和數組,直接量的建立和初始化都比非直接變量形式要快。
- 避免作重複的工做,當須要檢測瀏覽器時,可以使用延遲加載或條件預加載。
- 在進行數學計算時,考慮使用直接操做數字的二進制形式的位運算。
- javascript的原生方法總會比你寫的任何代碼都要快,儘可能使用原生方法。
第九章:構建並部署高性能的javascript應用
構建與部署的過程對基於javascript的web應用的性能有着巨大的影響。這個過程當中最重要的步驟有:
- 合併javascript文件以減小http請求數。
- 使用YUI Compressor壓縮javascript文件。
- 在服務器端壓縮javascript文件(Gzip編碼)。
- 經過正確設置HTTP響應頭來緩存javascript文件,經過向文件名增長時間戳來避免緩存問題。
- 使用CDN(Content Delivery Network)提供javascript文件,CDN不只能夠提高性能,它也爲你管理文件的壓縮與緩存。
全部這些步驟都應該自動化處理,可使用一些公用的工具,也能夠定置化工具來知足你的特定需求
第十章:工具
當網頁或web應用變慢時,分析從網絡下載的資源以及分析腳本的運行性能可以讓你專一於那些最須要優化的地方。
- 使用網絡分析工具找出加載腳本和頁面中其餘資源的瓶頸,這會幫助你決定哪些腳本須要延遲加載,或者須要進一步分析。
- 儘管傳統的經驗告訴咱們要儘可能減小HTTP請求數,但把腳本儘量延遲加載能夠加快頁面渲染速度,給用戶帶來更好的體驗。
- 使用性能分析工具找出腳本運行時過程當中速度慢的地方,檢查每一個函數所消耗的時間,以及函數被調用的次數,經過調用棧自身提供的一些線索來找出須要集中精力優化的地方。
- 儘管消耗的時間和調用次數一般是數據最有價值的部分,但仔細觀察函數的調用過程,你也許會發現其餘優化目標。
- 這些工具會幫助你深刻了解你的代碼在那些一般你比較陌生的編程環境下是如何運行的,在開始優化工做以前先使用它們,以確保開發時間用在刀刃上。
這本書很快就讀完了,基本講的就是雅虎優化的十四條軍規,雖然在現代大前端各類自動化工具的背景下,這些優化手段司空見慣,但在整個前端發展的道路上扮演了很重要的角色,現在有幸讀到這本老書,受益不淺,並分享出來以此共勉。