他們渲染了一百萬個網頁,來了解網絡如何崩潰

最近在 medium 上看到這篇「比較新鮮的」文章 《We rendered a million web pages to learn how the web breaks》 覺着不錯(老外確實敢想敢作),遂翻譯分享,以期拓寬視野、引人思考。本瓜不會去逐字翻譯,旦求一個表意流暢。其間也會或加入本身的見解,或引用其它。總之,事兒就是這麼個事兒,但願您喜歡~前端

爲何要渲染一百萬個頁面?

簡單來講,就是現現在出現一種爭議(argument):網絡從某種程度上來講比 15 年前更慢了。緣由是日益繁榮的 JS 框架、網絡字體、以及各種 polyfills 的增加,它們並無使得咱們從更高速的計算器、更快速的網絡通訊、更完備的網絡協議中獲益更多,甚至帶來了損害。webpack

So the argument goes.web

因而乎,做者團隊想證實這種說法是不是成立的,並嘗試找出致使 2020 年網站緩慢和崩潰的常見因素。編程

如何實現這一計劃?

做者團隊使用 Puppeteer 編寫了一個 Web 瀏覽器(Chrome)腳本,啓動 200 個 EC2 實例,讓它在週末運行,渲染排名前一百萬域名的根頁面。前端工程化

從這麼幾個統計指標看,這真是有夠瘋狂的。瀏覽器

在這個計劃中,他們跟蹤全部的 window.onerror 所捕獲的錯。安全

一般來講,咱們都會跟蹤客戶反饋的錯誤,可是這一次,跟蹤的倒是整個網絡的錯誤!此次將有足夠的說服力:研究網頁究竟是如何在實際運行中崩潰的?markdown

最多見的錯誤

分析數據代表,大多數問題均可以被歸類。而這,就能爲開發人員指引 Web 技術的將來發展方向:修復這一些小問題就能夠將 Web 的報錯數量減小十倍。網絡

這些壞傢伙TOP10 分別是(本瓜附 MDN 連接):app

  1. 引用錯誤
  2. 類型錯誤
  3. 語法錯誤
  4. Error
  5. 調用異常
  6. OneSignal
  7. 超出範圍
  8. Integration Error
  9. chunk 下載錯誤
  10. eval 計算錯誤

如 Tolstoy 所說:工做中的網址皆不相同,可是破壞它們的方式倒是一致的。如您所見,這些網絡錯誤的分佈符合【齊夫定律】。此例中,有三種錯誤佔了全部錯誤的極大比例。即:

引用錯誤(ReferenceError)、類型錯誤(TypeError)、語法錯誤(SyntaxError) 佔全部錯誤的 85%!

顯然,形成這些錯誤的方式有不少種,錯誤消息中的特定字符串會告訴咱們具體發生了什麼。做爲開發者,咱們必定經常遇到這其中的一些,並老是對它們感到熟悉。(這個錯誤我見過~)

固然,有不少方法能夠產生這些錯誤類型。 錯誤消息中的特定字符串告訴咱們更多有關實際發生的狀況的信息。 查看最多見的錯誤消息會給您必定的熟悉感。 做爲網絡開發人員,您以前可能已經遇到過其中一些。

讓咱們來看下具體的錯誤 TOP10 又是哪些?

  1. 找不到 $ 符(JQ 經典常見)
  2. 找不到 qq_qun(?)
  3. jQuery 未定義(常見)
  4. 意外的符號 '<'(常見)
  5. 無效或意外符號
  6. 沒法讀取 undefined 的 envelope 屬性(常見)
  7. $ 符不是一個函數(常見)
  8. 沒法讀取 null 的 addRventListener 屬性
  9. 意外的標識符
  10. 沒法讀取 null 的 appendChild 屬性

這些報錯都指向特定的錯誤消息,做者團隊繼續調試這些錯誤的樣本,來深刻了解它們的具體錯誤狀況。結果,意想不到的事情發生了:事實證實,對於引用錯誤(ReferenceError)和語法錯誤(SyntaxError)而言,有一個共通的根本緣由 —— 即 資源加載失敗,對於類型錯誤(TypeErrors),也有一個本質上的發現,即它們都屬於同一種問題。

做者團隊深刻研究產生了如下文章,描述了對每一個錯誤的發現:

How to resolve ReferenceError:咱們能夠獲取公共庫的高頻全局變量的使用趨勢,在此基礎上,構建相關聯的變量名和特定的庫來解決引用錯誤。即採用自定義高頻變量覆蓋公告庫來解決此類大部分問題。

What causes TypeError on live web sites:97% 的類型錯誤都來自於 null 或者 undefined。它們大多數是由於沒有符合第三方庫或者瀏覽器環境的依賴,或者是由於文檔對象發生錯誤致使選擇器拿不到值。

What causes SyntaxError on live web sites:開發過程當中,多數的語法錯誤來自於拼寫錯誤。實際運行中,多數的語法錯誤來自網絡故障或者 JS 的編寫錯誤。

如何預測錯誤數量?

做者團隊最初用邏輯迴歸和分類的方法(logistic regression classifier),嘗試根據 JS 所調用的庫來預測網站中錯誤的存在。基於此假設,意味着只要存在某些代碼,就預示着會致使錯誤。

繼續深刻分析顯示:大多數錯誤因爲缺乏代碼所致,因此這種方式的預測能力較低。可是,咱們能夠列一個分類器學習的迴歸係數。這就很高級了~ 它能夠顯示了這些分類選擇依賴的程度。事實上,一小段代碼在 webpack 的做用下將與一些錯誤強有力的鏈接起來,但它們對瀏覽器來講又是關鍵的依賴腳本。

這裏還有一個結論:用於追蹤 JS 錯誤的產品有更低的錯誤數。

讓我們來康康這些庫的迴歸係數,預測是否存在錯誤。

全部庫的邏輯迴歸係數,預測是否存在錯誤

例如,百度統計的迴歸係數大,表明缺失代碼的可能性較小,預測有更低的錯誤數。不過,本瓜懷疑和牆也有關係,由於一直在用谷歌統計,自覺更不錯啊~

網絡的錯誤恢復能力

在調研的一百萬個網頁中,有 12% 的網站存在一個或多個未處理的錯誤。這確實是一個驚人的數字。這些錯誤代表因爲某些意外的狀況停止了某些程序的執行,從而致使某些功能所以被破壞掉。

從 12% 也能看到 Web 的錯誤恢復能力是強大的:但不管你的錯誤是什麼,它都必須足夠小以致於懶得去修復它。

數據顯示:大多數錯誤來自於運行時缺乏代碼、數據、或文檔對象。頗有多是因爲 Web 的綁定特性決定的:類型在運行時(後期)才被肯定,而不是在編譯時(早期)就被肯定。 的確,在運行時才肯定類型可使得加載各種庫更輕鬆天然,但它也形成了一些錯誤發生的可能:便可能出現缺乏庫或者 API 發生了改變的狀況。固然,運行時才肯定類型不是惟一的選擇,許多語言都是在編譯時就已肯定了類型。

好比 Java Applets 構建的 Web,狀況將有所不一樣。(咱能從這個老古董裏學點什麼~)

如何構建不易出錯的網絡

在強類型系統的語言中嚴格要求定義類型,動態運行任何加載庫將變得艱難,尤爲是當這些庫的自定義程度很高,API 很開放的狀況。這不只與來源於網絡的代碼有關,也和瀏覽器的運行時有關。

咱們能夠稍微回顧下 Java Applets,若是你沒有正確安裝 Java 運行環境,那麼 applet 將拒絕運行直到你下載並安裝了相應的環境。在 Web 當中,你可使用舊瀏覽器查看頁面,但有瀏覽器和網站可能在長久的迭代中逐步崩潰(即運行環境也在變化)。不過,你也能夠編寫一個在當前版本瀏覽器和舊版本瀏覽器都能正常運行的網頁。根據這種思路,運行時綁定類型對於網絡的發展也是相當重要的!

2006 年,艾倫·凱(Alan Kay)和觀點研究所(Viewpoint Research Institute)發起了一項雄心勃勃的項目:以兩萬行代碼從裸機重構計算機至實現 GUI 操做系統。雖然這個項目因爲資金問題中途停滯,可是最終的報告仍是描述了一種運行時綁定的動態的語言的構建( late-bound references and dynamicity )—— KScript。這比 TypeScript 還要早 6 年!

艾倫·凱(Alan Kay)模仿了一個生態緊密的分佈式系統,沒有緊密互鎖的耦合。

截至此處,咱們尚未獲得最終的結論。靜態類型保證編譯器不出現某些類型錯誤,這是開發者喜聞樂見的。TypeScript 就頗有趣了,它跨越了動態類型和靜態類型,它須要付出這樣的代價:編譯器認爲編譯時期的類型可能不是運行時期的類型。

Web 的運行時綁定機制讓咱們總處於落後,若是瀏覽器不支持網頁的新特性,代碼就會中斷。對於 Web 而言,這彷佛比 Java Applet 模型「要麼沒有,要麼全有」的特色要好,在 Java Applet 中,只有在正確的運行環境裝好的狀況下才能運行程序。在 2000 年代初,XHTML 有相似的狀況。使用 XHTML,文檔需被要求是有效的 XML,無效的標記將致使頁面徹底不顯示。當時,這種行爲被許多人提倡,也許是由於無效的 HTML 被看做是致使瀏覽器有不一樣呈現的「主謀」。通過了十年的沉澱,有了更好的想法來標準化這些無效標記,並將它們合到了 HTML5 中。從目前的結果看,HTML5 賽過了 XHTML,JavaScript 賽過了 Java applet。

如今還有一匹黑馬,那就是 —— WebAssembly。有不少案例都是圍繞用靜態類型的語言將代碼編譯爲 wasm (好比 Blazor)。咱們正處在歷史潮頭,在這個時代,前端開發將再也不有大量的 JS 代碼。然而,這種思路下,技術若成爲一個個孤島也註定不會成功。從歷史中學習,咱們彷佛有必要圍繞動態找到一個更好的解決方案,並考慮運行時的綁定!

靜態類型語言能爲咱們提供安全性,動態類型語言又是 Web 不易出錯的關鍵。兩者的平衡是最終的關鍵!數據代表,當網絡中斷時,緣由是代碼沒有按預期運行,致使文檔錯誤、類型錯誤、三方庫或數據沒法加載等。咱們假設類型系統是解決編程問題的有辦法,它確保在編譯階段各類依賴就被作了檢查。是否存在一種人體工學ergonomic)的方法來實現這一目標?它能容許在動態環境中執行這種檢查,同時也就能消除困擾當今網絡的大多數錯誤。

做結

  1. 首先爲這個團隊的作法點贊,敢想敢作!實際上,研究崩潰只是整個研究的子課題,父課題爲 JavaScript Performance in the Wild 2020,其中還包括網絡鏈接狀況、第三方庫使用狀況、頁面渲染時間、請求數、重繪次數等等,有興趣點贊,本瓜後續接着翻。

  2. 咱們能夠預見的是 TypeScript 是目前解決 JS 類型問題的最好解決方案!也期待有更多解決方案,解決好比引用問題、語法問題,雖然這些 ESLint 也能作,但它只是插件工具。想有更多的遐想,或許編程語言自身就得足夠強大。

  3. Webpack 過重要了!在現在前端工程化的大環境下,開發儼然變成是對各類依賴庫的調用,而最終如何能打包成爲一個「趁心」的項目在線上運行,纔是關鍵中之關鍵。

  4. 就目前看,再遠一點的將來是 WebAssembly(給我往 si 裏學~)。

  5. 瀏覽器是 Web 前端攻城獅一切的基礎。說一個數據:谷歌瀏覽器 2008 年發佈,截至 2020 年,已有 69.89% 的市場佔有率。可是,誰還記得在 1990 年代中期,網景瀏覽器 的市場佔有率曾高達 90%?或許一切還未成定局!如做者所說,咱們處在歷史的潮頭。瀏覽器會去往何方?我們邊走邊看~

  6. 下降耦合、增高內聚的設計思想來 Coding,這不止於前端,這是計算器科學!

  7. 都看到這裏啦?點個贊吧?我是掘金安東尼,人不狠話也多......

相關文章
相關標籤/搜索