就像咱們以前文章中提到的渲染引擎同樣,咱們認爲好的和優秀的JavaScript開發人員之間的區別在於,後者不只瞭解語言的基本要素,還要了解其內部原理和周圍環境。chrome
四十九年前,建立了一個名爲ARPAnet的東西。這是一個早期的分組交換網絡,也是實現TCP / IP套件的第一個網絡。該網絡在加州大學和斯坦福研究院之間創建了聯繫。 20年後,Tim Berners-Lee發佈了一個名爲「Mesh」的提案,該提案後來更爲人稱爲萬維網。在那49年裏,互聯網已經走過了漫長的道路,從兩臺計算機交換數據包開始,到達超過7500萬臺服務器,38億人使用互聯網和1.3B網站。
瀏覽器
在這篇文章中,咱們將嘗試分析現代瀏覽器採用哪些技術來自動提高性能,而且咱們將特別放大瀏覽器網絡層。最後,咱們將提供一些關於如何幫助瀏覽器提高Web應用性能的想法。緩存
現代網絡瀏覽器專爲快速,高效和安全地交付網絡應用/網站而設計。數百個組件運行在不一樣的層上,從流程管理和安全沙箱到GPU流水線,音頻和視頻等等,Web瀏覽器看起來更像是一個操做系統,而不只僅是一個軟件應用程序。安全
瀏覽器的總體性能取決於許多大型組件:解析,佈局,樣式計算,JavaScript和WebAssembly執行,渲染,固然還有網絡堆棧。性能優化
工程師常常認爲網絡堆棧是一個瓶頸。這一般是這種狀況,由於在解除其餘步驟以前,須要從互聯網獲取全部資源。爲了提升網絡層的效率,它不只須要扮演簡單的套接字管理員的角色。它做爲一種很是簡單的資源獲取機制呈現給咱們,但它其實是一個擁有本身的優化標準,API和服務的整個平臺。
服務器
做爲Web開發人員,咱們沒必要擔憂單個TCP或UDP數據包,請求格式化,緩存和其餘全部事情。整個複雜性由瀏覽器處理,所以咱們能夠專一於咱們正在開發的應用程序。可是,瞭解發生了什麼,能夠幫助咱們建立更快,更安全的應用程序。cookie
實質上,用戶開始與瀏覽器交互時發生瞭如下狀況:網絡
W3C Navigation Timing規範提供瀏覽器API以及瀏覽器中每一個請求的生命週期背後的時間和性能數據。讓咱們來看看這些組件,由於它們在提供最佳用戶體驗方面起着相當重要的做用:
架構
整個聯網過程很是複雜,有許多不一樣的層次可能會成爲瓶頸。這就是爲何瀏覽器努力經過使用各類技術來提升性能的緣由,以便整個網絡通訊的影響最小。app
讓咱們從一些術語開始:
JavaScript和WebAssembly不容許咱們管理單個網絡套接字的生命週期,這是一件好事!這不只可讓咱們的手保持清潔,並且還可讓瀏覽器自動進行大量的性能優化,其中一些包括套接字重用,請求優先級和後期綁定,協議協商,強制鏈接限制等等。
實際上,現代瀏覽器會花費更多的時間來將請求管理週期與套接字管理分開。套接字按池組織,按原點分組,每一個池強制實施本身的鏈接限制和安全約束。待處理的請求排隊,優先,而後綁定到池中的單個套接字。除非服務器有意關閉鏈接,不然能夠在多個請求中自動重用相同的套接字!
因爲新的TCP鏈接的開通須要額外的成本,所以鏈接的重複使用對其自己具備很大的性能優點。默認狀況下,瀏覽器使用所謂的「keepalive」機制,這能夠節省在發出請求時打開新鏈接到服務器的時間。打開一個新的TCP鏈接的平均時間是:
這種架構打開了其餘一些優化機會的大門。這些請求能夠根據其優先級以不一樣的順序執行。瀏覽器能夠優化全部套接字上的帶寬分配,或者能夠在預期請求時打開套接字。
正如我以前提到的,這一切都是由瀏覽器管理的,並不須要咱們的任何工做。但這並不必定意味着咱們無能爲力。選擇正確的網絡通訊模式,傳輸類型和頻率,選擇協議以及調整/優化服務器堆棧能夠在提升應用程序的總體性能方面發揮重要做用。
有些瀏覽器甚至更進一步。例如,Chrome能夠自我教導本身在使用它時變得更快。它根據訪問的網站和典型的瀏覽模式進行學習,以便在用戶作任何事情以前預測可能的用戶行爲並採起行動。最簡單的例子是當用戶在連接上懸停時預先呈現頁面。若是您有興趣瞭解更多關於Chrome優化的信息,請參閱本章的https://www.igvita.com/posa/h...。
容許瀏覽器管理單個套接字具備另外一個很是重要的目的:經過這種方式,瀏覽器能夠對不可信的應用程序資源執行一致的安全和策略約束。例如,瀏覽器不容許直接API訪問原始網絡套接字,由於這可使任何惡意應用程序與任何主機進行任意鏈接。瀏覽器還強制執行鏈接限制,以保護服務器以及客戶端免受資源耗盡。
瀏覽器格式化全部傳出請求,以強化一致且格式良好的協議語義來保護服務器。一樣,響應解碼自動完成,以保護用戶免受惡意服務器的侵害。
傳輸層安全性(TLS)是一種經過計算機網絡提供通訊安全性的加密協議。它在許多應用程序中普遍使用,其中之一是網頁瀏覽。網站可使用TLS來保護其服務器和Web瀏覽器之間的全部通訊。
整個TLS握手由如下步驟組成:
客戶端向客戶端發送「Client hello」消息,以及客戶端的隨機值和支持的密碼套件。
服務器經過向客戶端發送「服務器問候」消息以及服務器的隨機值進行響應。
服務器將其證書發送給客戶端,並能夠向客戶端請求相似的證書。服務器發送「服務器已完成」消息。
若是服務器已經從客戶端請求證書,則客戶端發送它。
客戶端建立一個隨機的預主密鑰,並使用服務器證書中的公鑰對其進行加密,並將加密的預主密鑰發送給服務器。
服務器收到預主密鑰。服務器和客戶端根據預主密鑰生成主密鑰和會話密鑰。
客戶端向服務器發送「更改密碼規格」通知,指示客戶端將開始使用新的會話密鑰進行散列和加密消息。客戶端還發送「客戶端已完成」消息。
服務器收到「更改密碼規範」並使用會話密鑰將其記錄層安全狀態切換爲對稱加密。服務器向客戶端發送「服務器已完成」消息。
客戶端和服務器如今能夠經過他們創建的安全通道交換應用程序數據。全部從客戶端發送到服務器並返回的消息均使用會話密鑰加密。
若是任何驗證失敗 - 例如服務器正在使用自簽名證書,則警告用戶。
若是兩個頁面的協議,端口(若是指定了一個)和主機相同,則兩個頁面具備相同的來源。
如下是可能嵌入跨源的資源的一些示例:
帶有<script src =「...」> </ script>的JavaScript。語法錯誤的錯誤消息僅適用於同源腳本
CSS <link rel =「stylesheet」href =「...」>。因爲CSS的寬鬆語法規則,跨源CSS須要正確的Content-Type標頭。瀏覽器的限制因人而異
帶有<img>的圖像
帶有<video>和<audio>的媒體文件
帶有<object>,<embed>和<applet>的插件
帶有@ font-face的字體。有些瀏覽器容許使用交叉來源的字體,其餘瀏覽器則須要相同來源的字體。
任何與<frame>和<iframe>的東西。網站可使用X-Frame-Options標題來阻止這種形式的跨源交互。
以上列表遠非完整;其目標是突出工做中的「最小特權」原則。瀏覽器只公開應用程序代碼所需的API和資源:應用程序提供數據和URL,瀏覽器格式化請求並處理每一個鏈接的完整生命週期。
值得注意的是,「同源策略」沒有單一律念。相反,有一組相關機制強制限制DOM訪問,Cookie和會話狀態管理,網絡以及瀏覽器的其餘組件。
最好和最快的請求是未提出的請求。在分派請求以前,瀏覽器會自動檢查其資源緩存,執行必要的驗證檢查,並在知足指定條件時返回資源的本地副本。若是本地資源在高速緩存中不可用,則會發出網絡請求,而且響應會自動放入高速緩存中以供後續訪問(若是容許)。
管理高效和優化的資源緩存很困難。值得慶幸的是,瀏覽器表明了咱們的整個複雜性,咱們須要作的是確保咱們的服務器返回適當的緩存指令;要了解更多信息,請參閱客戶端上的緩存資源。您確實爲網頁上的全部資源提供了Cache-Control,ETag和Last-Modified響應標頭,對嗎?
最後,瀏覽器常常被忽視但關鍵的功能是提供身份驗證,會話和cookie管理。瀏覽器爲每一個來源維護單獨的「Cookie JAR」,提供必要的應用程序和服務器API來讀取和寫入新的Cookie,會話和身份驗證數據,並自動附加和處理相應的HTTP頭以表明咱們自動執行整個過程。
一個例子:
將會話狀態管理推遲到瀏覽器的便利性的一個簡單但說明性示例:能夠在多個選項卡或瀏覽器窗口之間共享通過身份驗證的會話,反之亦然;單個選項卡中的註銷操做將使全部其餘打開的窗口中的打開會話失效。
走上提供網絡服務的階梯,咱們終於到達了應用程序API和協議。正如咱們所看到的,較低層提供了一系列關鍵服務:套接字和鏈接管理,請求和響應處理,各類安全策略的執行,緩存等等。每次咱們啓動一個HTTP或一個XMLHttpRequest,一個長期服務器發送的事件或WebSocket會話,或打開一個WebRTC鏈接,咱們都與這些底層服務的一部分或所有進行交互。
沒有單一的最佳協議或API。每一個非平凡的應用程序都須要根據各類需求混合使用不一樣的傳輸:與瀏覽器緩存的交互,協議開銷,消息延遲,可靠性,數據傳輸類型等等。某些協議可能提供低延遲傳輸(例如Server-Sent Events,WebSocket),但可能不符合其餘關鍵條件,例如在全部狀況下利用瀏覽器緩存或支持高效二進制傳輸的能力。