Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲精品一区亚洲精品,免费高清日本中文,一二三四日本视频中文

          整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          GitHub 十大頂級 JavaScript 開源項目

          本文中,我們將介紹GitHub上頂級的JavaScript開源項目。

          作者 | Isha Jauhari

          譯者 | 彎月,責編 | 屠敏

          以下為譯文:

          JavaScript是當今最全能的流行編程語言之一。JavaScript之所以如此受歡迎,是因為它與HTML以及CSS構(gòu)成了互聯(lián)網(wǎng)的核心,為我們提供了可視化的當今互聯(lián)網(wǎng)。

          盡管最初JavaScript的設計意圖是作為一門腳本語言,編寫前端Web應用程序,然而如今它已經(jīng)滲透了開發(fā)領(lǐng)域的方方面面。因此,JavaScript成為了GitHub(全球最大的軟件開發(fā)及共享平臺)用戶最常使用的語言,也就不足為奇了。

          GitHub是目前最主要的共享代碼和開源項目的平臺,自然有許多項目都是用JavaScript編寫的。 在本文中,我們將介紹GitHub上頂級的JavaScript開源項目。

          React:Facebook的JavaScript開源代碼庫

          React可以說是世界上使用最廣泛的開源項目之一,由Facebook創(chuàng)建。我們可以使用這個庫輕松地在Web應用程序中創(chuàng)建用戶界面。而且開發(fā)新功能也異常容易,開發(fā)人員也不必擔心影響到任何現(xiàn)有的代碼。

          React Native建立在React之上,它將React的功能擴展到了移動應用程序上,也促使React成為了廣泛使用的開發(fā)平臺。

          GitHub代碼庫鏈接:https://github.com/facebook/react

          TensorFlow.js

          在過去的幾年中,隨著人們對機器學習的興趣日益增加,涌現(xiàn)了很多為構(gòu)建更出色的庫而努力的項目,因為他們都希望降低創(chuàng)建機器學習模型的難度。著名的TensorFlow庫最初是用Python編寫的,后來又衍生出了JavaScript版的TensorFlow.js。

          在轉(zhuǎn)換為JavaScript后,我們就可以利用這個庫在Web應用程序中構(gòu)建和部署機器學習模型,而且還可以放到移動應用中。TensorFlow.js可以在瀏覽器中訓練機器學習模型,因此降低了服務器訓練模型的計算開銷。

          在這個庫的幫助下,我們可以將機器學習應用擴展到移動應用程序,盡管對于機器學習應用程序而言,移動設備的計算能力嚴重不足。

          GitHub代碼庫鏈接:https://github.com/tensorflow/tfjs

          Node.js

          Node.js是開源的Javascript運行時環(huán)境。它是在Chrome瀏覽器的V8引擎之上構(gòu)建的。沒有單獨的運行時環(huán)境,JavaScript只能直接在瀏覽器的環(huán)境中運行。但是有了Node.js以后,JavaScript可以像Python那樣,作為獨立的腳本語言運行。

          開發(fā)人員隨時可以在自己的機器上測試JavaScript,甚至不需要瀏覽器。因此,原本只能為各個網(wǎng)站帶來交互性的JavaScript功能幾乎擴展到了所有領(lǐng)域。

          GitHub代碼庫鏈接:https://github.com/nodejs/node

          AngularJS

          AngularJS是業(yè)界最古老的前端JavaScript開源框架之一。該框架最初由Mi?ko Hevery開發(fā),后來發(fā)展成了GitHub上排名前十的JavaScript項目之一。

          Angular開發(fā)的Web應用程序可以實現(xiàn)跨平臺,因為它們可與各種設備兼容,無論是移動設備、臺式機還是平板電腦。無論在速度,還是性能和可伸縮性方面,AngularJS都可以與其他框架一較高低。

          AngularJS的宣傳中稱其能夠滿足巨大的數(shù)據(jù)需求,其提供的可擴展基礎架構(gòu)可以支持Google等大規(guī)模的應用程序。

          GitHub代碼庫鏈接:https://github.com/angular/angular.js

          jQuery

          jQuery開源代碼庫可以大幅簡化客戶端的HTML腳本。它的座右銘是“少寫,多做”,而它也的確做到了。jQuery將最常見的JavaScript任務打包成了方法,從而減輕了編程的工作量,并提高了編程的效率。據(jù)估計,jQuery是網(wǎng)頁中使用率最高的庫。

          GitHub代碼庫鏈接:https://github.com/jquery/jquery

          npm

          npm的全稱是Node Package Manager,這個工具庫的功能正如其名。它可以管理已安裝的Node.js軟件包,還可以更方便地安裝其他軟件包。

          GitHub代碼庫鏈接:https://github.com/npm/cli

          Vue.js

          Vue.js是GitHub上獲星最多的JavaScript開源框架。Vue.js是用于構(gòu)建交互式用戶界面的開源JavaScript框架。Vue側(cè)重于與其他JavaScript庫的集成,旨在簡化和組織Web應用程序。最初由Evan You于2014年開發(fā)。

          Vue的宣傳中稱這是一個易于學習、使用和維護的漸進式JavaScript框架。

          GitHub代碼庫鏈接:https://github.com/vuejs/vue

          Ember.js

          Ember是一個JavaScript開源框架,它可以幫助開發(fā)人員創(chuàng)建可擴展的單頁Web應用程序,類似于AngularJS。Ember.js注重生產(chǎn)力、增強功能的簡便性以及對開發(fā)人員的友好性。

          Ember.js是目前對開發(fā)人員最友好的框架之一,新手只需幾分鐘即可構(gòu)建應用程序。 Netflix等許多人氣網(wǎng)站都使用了Ember。

          GitHub代碼庫鏈接:https://github.com/emberjs/ember.js

          MeteorJS

          Meteor是面向Web、移動和桌面的跨平臺開源平臺。Meteor實現(xiàn)了與其他各種JavaScript框架的無縫集成。 MeteorJS注重優(yōu)化代碼的規(guī)模、跨平臺兼容性以及與其他庫的集成。

          與其他框架不同,Meteor不僅限于前端Web應用程序,它還可以快速建立原型,以及自動適應數(shù)據(jù)的變化。除此之外,Meteor還提供了許多增強功能的大型界面。

          GitHub代碼庫鏈接:https://github.com/meteor/meteor

          Polymer

          Polymer是一個JavaScript開源庫,使用所謂的“ Web組件”構(gòu)建應用程序。鼓勵開發(fā)人員重用Web的小部件或塊,從而促進了各個Web元素的互操作性。這個想法已在許多大型項目中得到了應用,例如YouTube和Google Earth。

          GitHub代碼庫鏈接:https://github.com/Polymer/polymer

          除了上述開源項目之外,GitHub上還有很多項目也同樣出色。而且,這些項目還有很多正在開發(fā)的功能,敬請期待。

          原文:https://medium.com/javascript-in-plain-english/top-10-javascript-open-source-projects-on-github-d1a83d502e12

          本文為 CSDN 翻譯,轉(zhuǎn)載請注明來源出處。

          互聯(lián)網(wǎng)發(fā)展的早期,JavaScript就已經(jīng)成為支持網(wǎng)頁內(nèi)容交互體驗的基礎技術(shù)。隨著時間推移,JavaScript業(yè)已升級成為互聯(lián)網(wǎng)的核心技術(shù)。

          長期以來,我都在學習JavaScript。學習JS一時爽,一直學習一直爽。

          在學習過程中,接觸很多學習資料,圖書、視頻等不一而足。

          今天給大家介紹兩個線上教程,都是廣受好評的,相信你一定也看過。

          1 Mozilla 開發(fā)者社區(qū) JavaScript 教程

          https://developer.mozilla.org/zh-CN/docs/Web/JavaScript

          教程內(nèi)容:

          • 對于完全初學者
            • JavaScript 第一步
            • JavaScript 基本結(jié)構(gòu)
            • 介紹JavaScript 對象
          • JavaScript 指南
          • 中級內(nèi)容
            • 客戶端 Web API
            • 重新介紹 JavaScript(JS 教程)
            • JavaScript 數(shù)據(jù)結(jié)構(gòu)
            • 如何使用比較操作符
            • 閉包
          • 高級內(nèi)容
            • 繼承和原型鏈
            • 嚴格模式
            • JavaScript 類型數(shù)組
            • 內(nèi)存管理
            • 并發(fā)模型以及事件循環(huán)


          2 現(xiàn)代 JavaScript 教程

          https://zh.javascript.info/

          教程內(nèi)容:

          第 一 部分 JavaScript 編程語言

          在這兒我們將從頭開始學習 JavaScript,也會學習 OOP 等相關(guān)高級概念。

          第 二 部分 瀏覽器:文檔,事件,接口

          學習如何管理瀏覽器頁面:添加元素,操縱元素的大小和位置,動態(tài)創(chuàng)建接口并與訪問者互動。

          第 三 部分 其他文章

          教程的前兩部分未涉及的其他主題的內(nèi)容列表。此處沒有明確的層次結(jié)構(gòu),你可以按你需要的順序閱讀文章。

          能每一個前端工程師都想要理解瀏覽器的工作原理。

          我們希望知道從在瀏覽器地址欄中輸入 url 到頁面展現(xiàn)的短短幾秒內(nèi)瀏覽器究竟做了什么;

          我們希望了解平時常常聽說的各種代碼優(yōu)化方案是究竟為什么能起到優(yōu)化的作用;

          我們希望更細化的了解瀏覽器的渲染流程。

          瀏覽器的多進程架構(gòu)

          一個好的程序常常被劃分為幾個相互獨立又彼此配合的模塊,瀏覽器也是如此,以 Chrome 為例,它由多個進程組成,每個進程都有自己核心的職責,它們相互配合完成瀏覽器的整體功能,每個進程中又包含多個線程,一個進程內(nèi)的多個線程也會協(xié)同工作,配合完成所在進程的職責。

          對一些前端開發(fā)同學來說,進程和線程的概念可能會有些模糊,為了更好的理解瀏覽器的多進程架構(gòu),這里我們簡單討論一下進程和線程。

          進程(process)和線程(thread)


          進程就像是一個有邊界的生產(chǎn)廠間,而線程就像是廠間內(nèi)的一個個員工,可以自己做自己的事情,也可以相互配合做同一件事情。

          當我們啟動一個應用,計算機會創(chuàng)建一個進程,操作系統(tǒng)會為進程分配一部分內(nèi)存,應用的所有狀態(tài)都會保存在這塊內(nèi)存中,應用也許還會創(chuàng)建多個線程來輔助工作,這些線程可以共享這部分內(nèi)存中的數(shù)據(jù)。如果應用關(guān)閉,進程會被終結(jié),操作系統(tǒng)會釋放相關(guān)內(nèi)存。更生動的示意圖如下:

          一個進程還可以要求操作系統(tǒng)生成另一個進程來執(zhí)行不同的任務,系統(tǒng)會為新的進程分配獨立的內(nèi)存,兩個進程之間可以使用 IPC (Inter Process Communication)進行通信。很多應用都會采用這樣的設計,如果一個工作進程反應遲鈍,重啟這個進程不會影響應用其它進程的工作。

          如果對進程及線程的理解還存在疑惑,可以參考下述文章:

          http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

          瀏覽器的架構(gòu)

          有了上面的知識做鋪墊,我們可以更合理的討論瀏覽器的架構(gòu)了,其實如果要開發(fā)一個瀏覽器,它可以是單進程多線程的應用,也可以是使用 IPC 通信的多進程應用。


          不同瀏覽器的架構(gòu)模型

          不同瀏覽器采用了不同的架構(gòu)模式,這里并不存在標準,本文以 Chrome 為例進行說明 :

          Chrome 采用多進程架構(gòu),其頂層存在一個 Browser process 用以協(xié)調(diào)瀏覽器的其它進程。


          Chrome 的不同進程

          具體說來,Chrome 的主要進程及其職責如下:

          Browser Process:

          • 負責包括地址欄,書簽欄,前進后退按鈕等部分的工作;
          • 負責處理瀏覽器的一些不可見的底層操作,比如網(wǎng)絡請求和文件訪問;

          Renderer Process:

          • 負責一個 tab 內(nèi)關(guān)于網(wǎng)頁呈現(xiàn)的所有事情

          Plugin Process:

          • 負責控制一個網(wǎng)頁用到的所有插件,如 flash
          • GPU Process
          • 負責處理 GPU 相關(guān)的任務



          不同進程負責的瀏覽器區(qū)域示意圖

          Chrome 還為我們提供了「任務管理器」,供我們方便的查看當前瀏覽器中運行的所有進程及每個進程占用的系統(tǒng)資源,右鍵單擊還可以查看更多類別信息。

          通過「頁面右上角的三個點點點 — 更多工具 — 任務管理器」即可打開相關(guān)面板。

          Chrome 多進程架構(gòu)的優(yōu)缺點

          優(yōu)點

          某一渲染進程出問題不會影響其他進程

          更為安全,在系統(tǒng)層面上限定了不同進程的權(quán)限

          缺點

          由于不同進程間的內(nèi)存不共享,不同進程的內(nèi)存常常需要包含相同的內(nèi)容。

          為了節(jié)省內(nèi)存,Chrome 限制了最多的進程數(shù),最大進程數(shù)量由設備的內(nèi)存和 CPU 能力決定,當達到這一限制時,新打開的 Tab 會共用之前同一個站點的渲染進程。

          測試了一下在 Chrome 中打開不斷打開知乎首頁,在 Mac i5 8g 上可以啟動四十多個渲染進程,之后新打開 tab 會合并到已有的渲染進程中。

          Chrome 把瀏覽器不同程序的功能看做服務,這些服務可以方便的分割為不同的進程或者合并為一個進程。以 Broswer Process 為例,如果 Chrome 運行在強大的硬件上,它會分割不同的服務到不同的進程,這樣 Chrome 整體的運行會更加穩(wěn)定,但是如果 Chrome 運行在資源貧瘠的設備上,這些服務又會合并到同一個進程中運行,這樣可以節(jié)省內(nèi)存,示意圖如下。

          iframe 的渲染 – Site Isolation

          在上面的進程圖中我們還可以看到一些進程下還存在著 Subframe,這就是 Site Isolation 機制作用的結(jié)果。

          Site Isolation 機制從 Chrome 67 開始默認啟用。這種機制允許在同一個 Tab 下的跨站 iframe 使用單獨的進程來渲染,這樣會更為安全。


          iframe 會采用不同的渲染進程

          Site Isolation 被大家看做里程碑式的功能, 其成功實現(xiàn)是多年工程努力的結(jié)果。Site Isolation 不是簡單的疊加多個進程。這種機制在底層改變了 iframe 之間通信的方法,Chrome 的其它功能都需要做對應的調(diào)整,比如說 devtools 需要相應的支持,甚至 Ctrl + F 也需要支持。關(guān)于 Site Isolation 的更多內(nèi)容可參考下述鏈接:

          https://developers.google.com/web/updates/2018/07/site-isolation

          介紹完了瀏覽器的基本架構(gòu)模式,接下來我們看看一個常見的導航過程對瀏覽器來說究竟發(fā)生了什么。

          導航過程發(fā)生了什么

          也許大多數(shù)人使用 Chrome 最多的場景就是在地址欄輸入關(guān)鍵字進行搜索或者輸入地址導航到某個網(wǎng)站,我們來看看瀏覽器是怎么看待這個過程的。

          我們知道瀏覽器 Tab 外的工作主要由 Browser Process 掌控,Browser Process 又對這些工作進一步劃分,使用不同線程進行處理:

          • UI thread : 控制瀏覽器上的按鈕及輸入框;
          • network thread: 處理網(wǎng)絡請求,從網(wǎng)上獲取數(shù)據(jù);
          • storage thread: 控制文件等的訪問;



          瀏覽器主進程中的不同線程

          回到我們的問題,當我們在瀏覽器地址欄中輸入文字,并點擊回車獲得頁面內(nèi)容的過程在瀏覽器看來可以分為以下幾步:

          1. 處理輸入

          UI thread 需要判斷用戶輸入的是 URL 還是 query;

          2. 開始導航

          當用戶點擊回車鍵,UI thread 通知 network thread 獲取網(wǎng)頁內(nèi)容,并控制 tab 上的 spinner 展現(xiàn),表示正在加載中。

          network thread 會執(zhí)行 DNS 查詢,隨后為請求建立 TLS 連接。


          UI thread 通知 Network thread 加載相關(guān)信息

          如果 network thread 接收到了重定向請求頭如 301,network thread 會通知 UI thread 服務器要求重定向,之后,另外一個 URL 請求會被觸發(fā)。

          3. 讀取響應

          當請求響應返回的時候,network thread 會依據(jù) Content-Type 及 MIME Type sniffing 判斷響應內(nèi)容的格式。


          判斷響應內(nèi)容的格式

          如果響應內(nèi)容的格式是 HTML ,下一步將會把這些數(shù)據(jù)傳遞給 renderer process,如果是 zip 文件或者其它文件,會把相關(guān)數(shù)據(jù)傳輸給下載管理器。

          Safe Browsing 檢查也會在此時觸發(fā),如果域名或者請求內(nèi)容匹配到已知的惡意站點,network thread 會展示一個警告頁。此外 CORB 檢測也會觸發(fā)確保敏感數(shù)據(jù)不會被傳遞給渲染進程。


          4. 查找渲染進程

          當上述所有檢查完成,network thread 確信瀏覽器可以導航到請求網(wǎng)頁,network thread 會通知 UI thread 數(shù)據(jù)已經(jīng)準備好,UI thread 會查找到一個 renderer process 進行網(wǎng)頁的渲染。


          收到 Network thread 返回的數(shù)據(jù)后,UI thread 查找相關(guān)的渲染進程

          由于網(wǎng)絡請求獲取響應需要時間,這里其實還存在著一個加速方案。當 UI thread 發(fā)送 URL 請求給 network thread 時,瀏覽器其實已經(jīng)知道了將要導航到那個站點。UI thread 會并行的預先查找和啟動一個渲染進程,如果一切正常,當 network thread 接收到數(shù)據(jù)時,渲染進程已經(jīng)準備就緒了,但是如果遇到重定向,準備好的渲染進程也許就不可用了,這時候就需要重啟一個新的渲染進程。

          5. 確認導航

          進過了上述過程,數(shù)據(jù)以及渲染進程都可用了, Browser Process 會給 renderer process 發(fā)送 IPC 消息來確認導航,一旦 Browser Process 收到 renderer process 的渲染確認消息,導航過程結(jié)束,頁面加載過程開始。

          此時,地址欄會更新,展示出新頁面的網(wǎng)頁信息。history tab 會更新,可通過返回鍵返回導航來的頁面,為了讓關(guān)閉 tab 或者窗口后便于恢復,這些信息會存放在硬盤中。


          6. 額外的步驟

          一旦導航被確認,renderer process 會使用相關(guān)的資源渲染頁面,下文中我們將重點介紹渲染流程。當 renderer process 渲染結(jié)束(渲染結(jié)束意味著該頁面內(nèi)的所有的頁面,包括所有 iframe 都觸發(fā)了 onload 時),會發(fā)送 IPC 信號到 Browser process, UI thread 會停止展示 tab 中的 spinner。


          Renderer Process 發(fā)送 IPC 消息通知 browser process 頁面已經(jīng)加載完成。

          當然上面的流程只是網(wǎng)頁首幀渲染完成,在此之后,客戶端依舊可下載額外的資源渲染出新的視圖。

          在這里我們可以明確一點,所有的 JS 代碼其實都由 renderer Process 控制的,所以在你瀏覽網(wǎng)頁內(nèi)容的過程大部分時候不會涉及到其它的進程。不過也許你也曾經(jīng)監(jiān)聽過 beforeunload 事件,這個事件再次涉及到 Browser Process 和 renderer Process 的交互,當當前頁面關(guān)閉時(關(guān)閉 Tab ,刷新等等),Browser Process 需要通知 renderer Process 進行相關(guān)的檢查,對相關(guān)事件進行處理。


          瀏覽器進程發(fā)送 IPC 消息給渲染進程,通知要離開當前網(wǎng)站了

          如果導航由 renderer process 觸發(fā)(比如在用戶點擊某鏈接,或者 JS 執(zhí)行 window.location = "http://newsite.com" ) renderer process 會首先檢查是否有 beforeunload 事件處理器,導航請求由 renderer process 傳遞給 Browser process。

          如果導航到新的網(wǎng)站,會啟用一個新的 render process 來處理新頁面的渲染,老的進程會留下來處理類似 unload 等事件。

          關(guān)于頁面的生命周期,更多內(nèi)容可參考 Page Lifecycle API 。


          瀏覽器進程發(fā)送 IPC 消息到新的渲染進程通知渲染新的頁面,同時通知舊的渲染進程卸載。

          除了上述流程,有些頁面還擁有 Service Worker (服務工作線程),Service Worker 讓開發(fā)者對本地緩存及判斷何時從網(wǎng)絡上獲取信息有了更多的控制權(quán),如果 Service Worker 被設置為從本地 cache 中加載數(shù)據(jù),那么就沒有必要從網(wǎng)上獲取更多數(shù)據(jù)了。

          值得注意的是 service worker 也是運行在渲染進程中的 JS 代碼,因此對于擁有 Service Worker 的頁面,上述流程有些許的不同。

          當有 Service Worker 被注冊時,其作用域會被保存,當有導航時,network thread 會在注冊過的 Service Worker 的作用域中檢查相關(guān)域名,如果存在對應的 Service worker,UI thread 會找到一個 renderer process 來處理相關(guān)代碼,Service Worker 可能會從 cache 中加載數(shù)據(jù),從而終止對網(wǎng)絡的請求,也可能從網(wǎng)上請求新的數(shù)據(jù)。


          Service Worker 依據(jù)具體情形做處理。

          關(guān)于 Service Worker 的更多內(nèi)容可參考:

          https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle

          如果 Service Worker 最終決定通過網(wǎng)上獲取數(shù)據(jù),Browser 進程 和 renderer 進程的交互其實會延后數(shù)據(jù)的請求時間 。Navigation Preload 是一種與 Service Worker 并行的加速加載資源的機制,服務端通過請求頭可以識別這類請求,而做出相應的處理。

          更多內(nèi)容可參考:

          https://developers.google.com/web/updates/2017/02/navigation-preload

          渲染進程是如何工作的?

          渲染進程幾乎負責 Tab 內(nèi)的所有事情,渲染進程的核心目的在于轉(zhuǎn)換 HTML CSS JS 為用戶可交互的 web 頁面。渲染進程中主要包含以下線程:


          渲染進程包含的線程

          1. 主線程 Main thread

          2. 工作線程 Worker thread

          3. 排版線程 Compositor thread

          4. 光柵線程 Raster thread

          后文我們將逐步介紹不同線程的職責,在此之前我們先看看渲染的流程。

          1. 構(gòu)建 DOM

          當渲染進程接收到導航的確認信息,開始接受 HTML 數(shù)據(jù)時,主線程會解析文本字符串為 DOM。

          渲染 html 為 DOM 的方法由 HTML Standard 定義。

          2. 加載次級的資源

          網(wǎng)頁中常常包含諸如圖片,CSS,JS 等額外的資源,這些資源需要從網(wǎng)絡上或者 cache 中獲取。主進程可以在構(gòu)建 DOM 的過程中會逐一請求它們,為了加速 preload scanner 會同時運行,如果在 html 中存在 <img><link> 等標簽,preload scanner 會把這些請求傳遞給 Browser process 中的 network thread 進行相關(guān)資源的下載。

          3.JS 的下載與執(zhí)行

          當遇到 <script> 標簽時,渲染進程會停止解析 HTML,而去加載,解析和執(zhí)行 JS 代碼,停止解析 html 的原因在于 JS 可能會改變 DOM 的結(jié)構(gòu)(使用諸如 documwnt.write()等 API)。

          不過開發(fā)者其實也有多種方式來告知瀏覽器應對如何應對某個資源,比如說如果在<script> 標簽上添加了 async 或 defer 等屬性,瀏覽器會異步的加載和執(zhí)行 JS 代碼,而不會阻塞渲染。更多的方法可參考 Resource Prioritization – Getting the Browser to Help You。

          4. 樣式計算

          僅僅渲染 DOM 還不足以獲知頁面的具體樣式,主進程還會基于 CSS 選擇器解析 CSS 獲取每一個節(jié)點的最終的計算樣式值。即使不提供任何 CSS,瀏覽器對每個元素也會有一個默認的樣式。


          渲染進程主線程計算每一個元素節(jié)點的最終樣式值

          5. 獲取布局

          想要渲染一個完整的頁面,除了獲知每個節(jié)點的具體樣式,還需要獲知每一個節(jié)點在頁面上的位置,布局其實是找到所有元素的幾何關(guān)系的過程。其具體過程如下:

          通過遍歷 DOM 及相關(guān)元素的計算樣式,主線程會構(gòu)建出包含每個元素的坐標信息及盒子大小的布局樹。布局樹和 DOM 樹類似,但是其中只包含頁面可見的元素,如果一個元素設置了 display:none ,這個元素不會出現(xiàn)在布局樹上,偽元素雖然在 DOM 樹上不可見,但是在布局樹上是可見的。


          6. 繪制各元素

          即使知道了不同元素的位置及樣式信息,我們還需要知道不同元素的繪制先后順序才能正確繪制出整個頁面。在繪制階段,主線程會遍歷布局樹以創(chuàng)建繪制記錄。繪制記錄可以看做是記錄各元素繪制先后順序的筆記。


          主線程依據(jù)布局樹構(gòu)建繪制記錄

          7. 合成幀

          熟悉 PS 等繪圖軟件的童鞋肯定對圖層這一概念不陌生,現(xiàn)代 Chrome 其實利用了這一概念來組合不同的層。

          復合是一種分割頁面為不同的層,并單獨柵格化,隨后組合為幀的技術(shù)。不同層的組合由 compositor 線程(合成器線程)完成。

          主線程會遍歷布局樹來創(chuàng)建層樹(layer tree),添加了 will-change CSS 屬性的元素,會被看做單獨的一層。


          主線程遍歷布局樹生成層樹

          你可能會想給每一個元素都添加上 will-change,不過組合過多的層也許會比在每一幀都柵格化頁面中的某些小部分更慢。為了更合理的使用層,可參考 堅持僅合成器的屬性和管理層計數(shù) 。

          一旦層樹被創(chuàng)建,渲染順序被確定,主線程會把這些信息通知給合成器線程,合成器線程會柵格化每一層。有的層的可以達到整個頁面的大小,因此,合成器線程將它們分成多個磁貼,并將每個磁貼發(fā)送到柵格線程,柵格線程會柵格化每一個磁貼并存儲在 GPU 顯存中。


          柵格線程會柵格化每一個磁貼并存儲在 GPU 顯存中

          一旦磁貼被光柵化,合成器線程會收集稱為繪制四邊形的磁貼信息以創(chuàng)建合成幀。

          合成幀隨后會通過 IPC 消息傳遞給瀏覽器進程,由于瀏覽器的 UI 改變或者其它拓展的渲染進程也可以添加合成幀,這些合成幀會被傳遞給 GPU 用以展示在屏幕上,如果滾動發(fā)生,合成器線程會創(chuàng)建另一個合成幀發(fā)送給 GPU。


          合成器線程會發(fā)送合成幀給 GPU 渲染

          合成器的優(yōu)點在于,其工作無關(guān)主線程,合成器線程不需要等待樣式計算或者 JS 執(zhí)行,這就是為什么合成器相關(guān)的動畫 最流暢,如果某個動畫涉及到布局或者繪制的調(diào)整,就會涉及到主線程的重新計算,自然會慢很多。

          瀏覽器對事件的處理

          瀏覽器通過對不同事件的處理來滿足各種交互需求,這一部分我們一起看看從瀏覽器的視角,事件是什么,在此我們先主要考慮鼠標事件。

          在瀏覽器的看來,用戶的所有手勢都是輸入,鼠標滾動,懸置,點擊等等都是。

          當用戶在屏幕上觸發(fā)諸如 touch 等手勢時,首先收到手勢信息的是 Browser process, 不過 Browser process 只會感知到在哪里發(fā)生了手勢,對 tab 內(nèi)內(nèi)容的處理是還是由渲染進程控制的。

          事件發(fā)生時,瀏覽器進程會發(fā)送事件類型及相應的坐標給渲染進程,渲染進程隨后找到事件對象并執(zhí)行所有綁定在其上的相關(guān)事件處理函數(shù)。


          事件從瀏覽器進程傳送給渲染進程

          前文中,我們提到過合成器可以獨立于主線程之外通過合成柵格化層平滑的處理滾動。如果頁面中沒有綁定相關(guān)事件,組合器線程可以獨立于主線程創(chuàng)建組合幀。如果頁面綁定了相關(guān)事件處理器,主線程就不得不出來工作了。這時候合成器線程會怎么處理呢?

          這里涉及到一個專業(yè)名詞「理解非快速滾動區(qū)域(non-fast scrollable region)」由于執(zhí)行 JS 是主線程的工作,當頁面合成時,合成器線程會標記頁面中綁定有事件處理器的區(qū)域為 non-fast scrollable region ,如果存在這個標注,合成器線程會把發(fā)生在此處的事件發(fā)送給主線程,如果事件不是發(fā)生在這些區(qū)域,合成器線程則會直接合成新的幀而不用等到主線程的響應。


          涉及 non-fast scrollable region 的事件,合成器線程會通知主線程進行相關(guān)處理。

          web 開發(fā)中常用的事件處理模式是事件委托,基于事件冒泡,我們常常在最頂層綁定事件:

          復制代碼

          document.body.addEventListener('touchstart', 
          event => {
           if (event.target === area) {
           event.preventDefault();
           }
          }
          );
           
          

          上述做法很常見,但是如果從瀏覽器的角度看,整個頁面都成了 non-fast scrollable region 了。

          這意味著即使操作的是頁面無綁定事件處理器的區(qū)域,每次輸入時,合成器線程也需要和主線程通信并等待反饋,流暢的合成器獨立處理合成幀的模式就失效了。


          由于事件綁定在最頂部,整個頁面都成為了 non-fast scrollable region。

          為了防止這種情況,我們可以為事件處理器傳遞 passive: true 做為參數(shù),這樣寫就能讓瀏覽器即監(jiān)聽相關(guān)事件,又讓組合器線程在等等主線程響應前構(gòu)建新的組合幀。

          復制代碼

          document.body.addEventListener('touchstart', 
          event => {
           if (event.target === area) {
           event.preventDefault()
           }
           }, {passive: true}
          );
           
          

          不過上述寫法可能又會帶來另外一個問題,假設某個區(qū)域你只想要水平滾動,使用 passive: true 可以實現(xiàn)平滑滾動,但是垂直方向的滾動可能會先于event.preventDefault()發(fā)生,此時可以通過 event.cancelable 來防止這種情況。

          復制代碼

          document.body.addEventListener('pointermove', event => {
           if (event.cancelable) {
           event.preventDefault(); // block the native scroll
           /*
           * do what you want the application to do here
           */
           } 
          }, {passive: true});
           
          

          也可以使用 css 屬性 touch-action 來完全消除事件處理器的影響,如:

          復制代碼

          #area { 
           touch-action: pan-x; 
          }
           
          

          查找到事件對象

          當組合器線程發(fā)送輸入事件給主線程時,主線程首先會進行命中測試(hit test)來查找對應的事件目標,命中測試會基于渲染過程中生成的繪制記錄( paint records )查找事件發(fā)生坐標下存在的元素。


          主線程依據(jù)繪制記錄查找事件相關(guān)元素。

          事件的優(yōu)化

          一般我們屏幕的刷新速率為 60fps,但是某些事件的觸發(fā)量會不止這個值,出于優(yōu)化的目的,Chrome 會合并連續(xù)的事件 (如 wheel, mousewheel, mousemove, pointermove, touchmove ),并延遲到下一幀渲染時候執(zhí)行 。

          而如 keydown, keyup, mouseup, mousedown, touchstart, 和 touchend 等非連續(xù)性事件則會立即被觸發(fā)。


          Chrome 會合并連續(xù)事件到下一幀觸發(fā)。

          合并事件雖然能提示性能,但是如果你的應用是繪畫等,則很難繪制一條平滑的曲線了,此時可以使用 getCoalescedEvents API 來獲取組合的事件。示例代碼如下:

          復制代碼

          window.addEventListener('pointermove', event => {
           const events = event.getCoalescedEvents();
           for (let event of events) {
           const x = event.pageX;
           const y = event.pageY;
           // draw a line using x and y coordinates.
           }
          });
           
          



          花了好久來整理上面的內(nèi)容,整理的過程收獲還挺大的,也希望這篇筆記能對你有所啟發(fā),如果有任何疑問,歡迎一起來討論。

          本文經(jīng)作者授權(quán)轉(zhuǎn)載,原文鏈接為:

          https://zhuanlan.zhihu.com/p/47407398

          參考鏈接

          • https://developers.google.com/web/updates/2018/09/inside-browser-part1
          • https://developers.google.com/web/updates/2018/09/inside-browser-part2
          • https://developers.google.com/web/updates/2018/09/inside-browser-part3
          • https://developers.google.com/web/updates/2018/09/inside-browser-part4
          • https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/#Layered_representation

          主站蜘蛛池模板: 精品视频一区二区三区| 亚洲AV无码一区二区乱子伦| 夜夜爽一区二区三区精品| 久久精品国产免费一区| 精品无码日韩一区二区三区不卡| 在线成人综合色一区| 亚洲乱码国产一区三区| 久久久久久人妻一区二区三区| 亚洲AV福利天堂一区二区三| 一区二区三区中文字幕| 无码国产精品一区二区高潮| 亚洲av成人一区二区三区观看在线| 国产日韩一区二区三免费高清| 日本免费一区尤物| 色综合视频一区二区三区44| 亚洲综合一区二区国产精品| 在线精品国产一区二区三区| 无码日韩人妻AV一区免费l| 亚洲AV日韩AV一区二区三曲| 亚洲国产高清在线精品一区| 久久一区二区精品综合| 免费av一区二区三区| 中文字幕无码一区二区免费| 久久无码人妻精品一区二区三区| 无码毛片一区二区三区中文字幕 | 国产激情一区二区三区成人91 | 中文字幕不卡一区| 免费视频精品一区二区| 性盈盈影院免费视频观看在线一区 | 成人一区二区三区视频在线观看| 无码丰满熟妇一区二区| 天海翼一区二区三区高清视频| 亚洲乱码一区二区三区国产精品| 亚洲av无码片区一区二区三区| 天堂一区人妻无码| 精品3d动漫视频一区在线观看| 一区二区三区四区国产| 在线观看午夜亚洲一区| 91午夜精品亚洲一区二区三区| 91精品乱码一区二区三区| 无码人妻精一区二区三区 |