瀏覽器組成和各引擎工做原理

1.瀏覽器的主要構成部分

  • 1.用戶界面
  • 2.瀏覽器引擎(負責窗口管理、Tab進程管理等)
  • 3.渲染引擎(有叫內核,負責HTML解析、頁面渲染)
  • 4.JS引擎(JS解釋器,如Chrome和Nodejs採用的V8)

圖片描述

這裏面最核心的就是渲染引擎和JS引擎,後面會詳細介紹這兩個引擎的相關內容。javascript

常見瀏覽器的渲染引擎和JS引擎以下:html

瀏覽器 渲染引擎 JS引擎
IE Trident Chakra
Edge EdgeHTML Chakra
Firefox Gecko SpiderMonkey
Chrome Webkit -> Blink V8(著名的)
Safri Webkit Javascriptcore
Opera Presto->Blink Carakan

注:新版本的Chrome採用的渲染引擎是Blink,Blink是由谷歌團隊從Webkit衍生開發出來的引擎,主要有應用到Chrome和Opera瀏覽器。vue

2.從進程和線程的角度來理解瀏覽器工做

1)進程和線程

  • 進程是cpu資源分配的最小單位(是能擁有資源和獨立運行的最小單位)
  • 線程是cpu調度的最小單位(線程是創建在進程的基礎上的一個程序運行單位,一個進程中能夠有多個線程)

進程能夠類比爲工廠,線程就是工廠裏面的工人,一個工廠能夠包含一個或者多個工人,工人之間能夠相互協做,而且共享工做空間java

2)瀏覽器的多進程架構

現代的瀏覽器採用的都是多進程架構,主要包含如下三種進程:git

1.Browser進程github

瀏覽器的主線程,主要負責瀏覽器的頁面管理、書籤、前進後退、資源下載管理等,整個瀏覽器應用程序只有一個,對應上述瀏覽器組成中的瀏覽器引擎。ajax

2.渲染進程npm

內核進程、負責頁面渲染、JS執行,對應的是上述的渲染引擎和JS引擎,一個瀏覽器能夠包含多個渲染進程,每一個Tab窗口頁對應一個渲染進程promise

3.GPU進程瀏覽器

負責GPU渲染,整個瀏覽器應用程序只有一個

4.插件進程

瀏覽器安裝的插件(擴展程序),每一個插件會建立一個進程

圖片描述

當打開上面兩個Tab時,Chrome任務管理器截圖:主要包括

  • 1個瀏覽器進程
  • 1個GPU進程
  • 1個網絡進程
  • 2個渲染進程(對應一個Tab一個進程)
  • 4個擴展程序進程

圖片描述

MAC的活動監視器中的chorme進程,能夠看到全部的渲染、擴展、GPU、網絡進程都統一顯示爲Google Chrome Helper。

圖片描述

這種多進程瀏覽器架構主要有以下優點:

  • 1.避免單個頁面奔潰影響整個瀏覽器
  • 2.避免第三方插件奔潰影響整個瀏覽器
  • 3.充分利用多核優點

3)瀏覽器的渲染進程

  • 瀏覽器有多個渲染進程、一個Tab頁面一個(相同的Tab頁面可能會被合併)
  • 一個渲染進程包含多個線程

一個渲染進程主要包括以下線程:

1.GUI線程(主要負責解析HTML、CSS和渲染頁面)

2.JS引擎線程(負責解析和執行JS代碼)

3.事件線程(控制事件循環)

4.定時器線程(處理定時器相關邏輯)

5.異步請求線程(發起Ajax時會生成該線程)

線程規則:

1.GUI渲染線程與JS引擎線程是互斥的,當JS引擎執行時GUI線程會被掛起,頁面的更新操做會等到JS引擎空閒時執行,涉及任務和微任務相關知識

2.一個渲染進程同時只有一個JS解析線程在運行

3.JS引擎線程不停的處理事件線程推送到事件隊列中的任務

4.定時器和異步請求最終生成的回調事件也有事件線程來控制和管理

瞭解了瀏覽器的渲染進程以後咱們再來看看JS引擎。

4)從事件循環的角度來理解JS引擎的工做過程

在理解什麼是事件循環以前,咱們先來了解下同步和異步的概念

1.同步和異步

同步是代碼執行後就能夠得到想要的結果,異步是指代碼執行以後不能當即得到結果,

你打電話問書店老闆有沒有《Javascript權威指南》這本書,若是是同步通訊機制,書店老闆會說,你稍等,」我查一下",而後開始查啊查,等查好了(多是5秒,也多是一天)告訴你結果(返回結果)。
而異步機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,而後直接掛電話了(不返回結果)。而後查好了,他會主動打電話給你。在這裏老闆經過「回電」這種方式來返回結果。

2.同步任務和異步任務

同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;異步任務指的是,不進入主線程、而是由事件線程調度,在知足執行條件的時候放到事件隊列中,等待主線程(JS線程)的執行。

3.爲何要有事件循環的概念

JS包含有異步操做(如:Ajax、定時器),這些異步操做完成以後須要通知JS引擎來處理異步操做的返回,如Ajax的Callback。這些異步操做何時完成是不肯定的,因此須要有一個事件隊列,事件線程將已經完成的異步操做的回調任務加載到事件隊列中,JS引擎在執行完當前的同步任務以後循環從事件隊列中取事件執行。

異步任務:setTImeout、setInterval、Promise、process.nextTick(Node.js)、Ajax

同步任務:除以上異步任務

同步任務和異步任務的執行流程以下:

異步任務統一有事件線程管理,當異步任務完成的時候會被放入到事件隊列中,JS在順序執行完當前的代碼以後會從事件隊列中讀取任務,再重複整個流程,判斷該任務是同步仍是異步。

圖片描述

4.異步任務的優先級

若是按照上述的簡化理解,全部異步任務都按照知足執行條件的順序放到事件隊列中,世界很和平,先來先到,可是在ES6當中,引入了microtask的概念,microtask會在當前的任務執行完成以後當即執行。由於咱們將異步任務分爲task和microtask,咱們又稱爲宏任務和微任務。

task:setTImeout、setInterval、ajax

microtask:MutationObserve、promise、process.nextTick(Node.js)

這樣子加了優先級的話JS的執行又會變得再複雜一點,以下圖所示,異步任務執行完成以後會判斷他是task仍是microtask,再分別加到不一樣的時間隊列中,JS當前任務執行完成以後優先清空當前的microtask隊列,並且在每次執行完宏任務的時候都會去清空微任務。

圖片描述

示例:

運行以下示例,就能夠驗證上述執行流程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="outer">
          <div class="inner"></div>
    </div>
    <script>
        // Let's get hold of those elements
        var outer = document.querySelector('.outer');
        var inner = document.querySelector('.inner');
        // Let's listen for attribute changes on the
        // outer element
        new MutationObserver(function() {
          console.log('mutate');
        }).observe(outer, {
          attributes: true
        });
        // Here's a click listener…
        function onClick() {
          console.log('click');
          setTimeout(function() {
            console.log('timeout');
          }, 0);
          Promise.resolve().then(function() {
            console.log('promise');
          });
          outer.setAttribute('data-random', Math.random());
        }
        // …which we'll attach to both elements
        inner.addEventListener('click', onClick);
        outer.addEventListener('click', onClick);
    </script>
</body>
</html>

5.UI渲染線程何時工做

UI渲染線程會在當前的Task執行完成以後,下一個Task執行以前執行,微任務會優先於UI渲染線程,這就意味着咱們使用微任務更新的DOM能更快的被渲染出來。另外Vue.js最新版本數據變動的時候採用的是promise和MutationObserver建立微任務:https://github.com/vuejs/vue/...

Demo:用於理解任務和UI渲染之間的關係

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue nextTick</title>
</head>
<body>
    <!-- jsFiddle例子:http://jsfiddle.net/gkmzns9u/14/ -->
    <div id="task">
        <div id="msg">
            {{msg}}
        </div>
        <div @click="greet">
            click me!
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script type="text/javascript">
        const vm = new Vue({
            el: '#task',
            data: {
                msg: 'hello'
            },
            methods: {
                greet: () => {
                    // 修改model,觸發set方法,調用update方法,添加DOM更新微任務
                      vm.msg  = 'hello world';
                      vm.msg  = 'hello world2';
                      // 查看DOM,因爲是異步更新DOM,根據EventLoop原理可知,這裏DOM尚未更新,
                      // hello
                    alert(document.getElementById('msg').innerHTML);
                    // nextTick使用promise,是個微任務,在當前greet方法執行完成以後會當即執行
                    vm.$nextTick().then(() => {
                        // 因爲DOM更新微任務先被添加,先入先出,這裏獲取的DOM已是更新好的
                        // hello world
                        alert(document.getElementById('msg').innerHTML);
                        // 直接修改DOM,同步任務
                        document.getElementById('msg').innerHTML = 'test'
                        // 當即生效
                        // test
                        alert(document.getElementById('msg').innerHTML);
                        /* 根據HTML Standard,一輪事件循環執行結束(包括微任務)以後,下輪事件循環執行以前開始進行UI render。即:macro-task任務執行完畢,接着執行完全部的micro-task任務後,此時本輪循環結束,開始執行UI render。UI render完畢以後接着下一輪循環。 */
                    });
                    // 因爲setTimeout爲宏任務,雖然延遲時間爲0,但仍是要晚於nextTick執行
                    // 並且能夠明顯看到在setTimeout回調執行以前頁面上已經渲染上test,說明UI Render已經在setTimeout回調以前執行
                    setTimeout(()=>{
                        alert('setTimeout start')
                        document.getElementById('msg').innerHTML = 'setTimeout'
                    }, 0)
                }
            }
        });
    </script>
</body>
</html>
相關文章
相關標籤/搜索