国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入前端-徹底搞懂JS的運行機制

luckyw / 780人閱讀

摘要:瀏覽器是多進程的詳情看我上篇總結瀏覽器執行機制的文章深入前端徹底搞懂瀏覽器運行機制瀏覽器每打開一個標簽頁,就相當于創建了一個獨立的瀏覽器進程。執行異步操作事件完成,回調函數進入。主線程從讀取回調函數并執行。

最近看了很多關于JS運行機制的文章,每篇都獲益匪淺,但各有不同,所以在這里對這幾篇文章里說的很精辟的地方做一個總結,參考文章鏈接見最后。本文博客地址
了解進程和線程

進程是應用程序的執行實例,每一個進程都是由私有的虛擬地址空間、代碼、數據和其它系統資源所組成;進程在運行過程中能夠申請創建和使用系統資源(如- 獨立的內存區域等),這些資源也會隨著進程的終止而被銷毀。

而線程則是進程內的一個獨立執行單元,在不同的線程之間是可以共享進程資源的,所以在多線程的情況下,需要特別注意對臨界資源的訪問控制。

在系統創建進程之后就開始啟動執行進程的主線程,而進程的生命周期和這個主線程的生命周期一致,主線程的退出也就意味著進程的終止和銷毀。

主線程是由系統進程所創建的,同時用戶也可以自主創建其它線程,這一系列的線程都會并發地運行于同一個進程中。

瀏覽器是多進程的
詳情看我上篇總結瀏覽器執行機制的文章-深入前端-徹底搞懂瀏覽器運行機制

瀏覽器每打開一個標簽頁,就相當于創建了一個獨立的瀏覽器進程。

Browser進程:瀏覽器的主進程(負責協調、主控),只有一個。作用有

第三方插件進程:每種類型的插件對應一個進程,僅當使用該插件時才創建

GPU進程:最多一個,用于3D繪制等

瀏覽器渲染進程(瀏覽器內核)

javascript是一門單線程語言

jS運行在瀏覽器中,是單線程的,但每個tab標簽頁都是一個進程,都含有不同JS線程分別執行,,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序

既然是單線程的,在某個特定的時刻只有特定的代碼能夠被執行,并阻塞其它的代碼。而瀏覽器是事件驅動的(Event driven),瀏覽器中很多行為是異步(Asynchronized)的,會創建事件并放入執行隊列中。javascript引擎是單線程處理它的任務隊列,你可以理解成就是普通函數和回調函數構成的隊列。當異步事件發生時,如(鼠標點擊事件發生、定時器觸發事件發生、XMLHttpRequest完成回調觸發等),將他們放入執行隊列,等待當前代碼執行完成。

javascript引擎是基于事件驅動單線程執行的,JS引擎一直等待著任務隊列中任務的到來,然后加以處理,瀏覽器無論什么時候都只有一個JS線程在運行JS程序。所以一切javascript版的"多線程"都是用單線程模擬出來的

為什么JavaScript是單線程?與它的用途有關。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,這時瀏覽器應該以哪個線程為準?

任務隊列

"任務隊列"是一個事件的隊列(也可以理解成消息的隊列),IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務可以進入"執行棧"了。主線程讀取"任務隊列",就是讀取里面有哪些事件。

"任務隊列"中的事件,除了IO設備的事件以外,還包括一些用戶產生的事件(比如鼠標點擊、頁面滾動等等),ajax請求等。只要指定過回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。

所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。

"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動進入主線程。但是,由于存在后文提到的"定時器"功能,主線程首先要檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。

同步和異步任務

既然js是單線程,那么問題來了,某一些非常耗時間的任務就會導致阻塞,難道必須等前面的任務一步一步執行玩嗎?
比如我再排隊就餐,前面很長的隊列,我一直在那里等豈不是很傻逼,說以就會有排號系統產生,我們訂餐后給我們一個號碼,叫到號碼直接去就行了,沒交我們之前我們可以去干其他的事情。
因此聰明的程序員將任務分為兩類:

同步任務:同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;

異步任務:異步任務指的是,不進入主線程、而進入"任務隊列"(Event queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。

任務有更精細的定義:

macro-task(宏任務):包括整體代碼script(同步宏任務),setTimeout、setInterval(異步宏任務)

micro-task(微任務):Promise,process.nextTick,ajax請求(異步微任務)

macrotask(又稱之為宏任務)

可以理解是每次執行棧執行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執行棧中執行)
每一個task會從頭到尾將這個任務執行完畢,不會執行其它
瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執行,會在一個task執行結束后,在下一個 task 執行開始前,對頁面進行重新渲染
(task->渲染->task->...)

microtask(又稱為微任務),可以理解是在當前 task 執行結束后立即執行的任務

也就是說,在當前task任務后,下一個task之前,在渲染之前
所以它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染
也就是說,在某一個macrotask執行完后,就會將在它執行期間產生的所有microtask都執行完畢(在渲染前)

執行機制與事件循環

主線程運行的時候,產生堆(heap)和棧(stack),棧中的代碼調用各種外部API,它們在"任務隊列"中加入各種事件(click,load,done)。只要棧中的代碼執行完畢,主線程就會去讀取"任務隊列",依次執行那些事件所對應的回調函數。

那怎么知道主線程執行棧為執行完畢?js引擎存在monitoring process進程,會持續不斷的檢查主線程執行棧是否為空,一旦為空,就會去Event Queue那里檢查是否有等待被調用的函數。

第一輪事件循環:
主線程執行js整段代碼(宏任務),將ajax、setTimeout、promise等回調函數注冊到Event Queue,并區分宏任務和微任務。
主線程提取并執行Event Queue 中的ajax、promise等所有微任務,并注冊微任務中的異步任務到Event Queue。
第二輪事件循環:
主線程提取Event Queue 中的第一個宏任務(通常是setTimeout)。
主線程執行setTimeout宏任務,并注冊setTimeout代碼中的異步任務到Event Queue(如果有)。
執行Event Queue中的所有微任務,并注冊微任務中的異步任務到Event Queue(如果有)。
類似的循環:宏任務每執行完一個,就清空一次事件隊列中的微任務。

注意:事件隊列中分“宏任務隊列”和“微任務隊列”,每執行一次任務都可能注冊新的宏任務或微任務到相應的任務隊列中,只要遵循“每執行一個宏任務,就會清空一次事件隊列中的所有微任務”這一循環規則,就不會弄亂。

說了那么多來點實例吧 ajax普通異步請求實例
let data = [];
$.ajax({
    url:www.javascript.com,
    data:data,
    success:() => {
        console.log("發送成功!");
    }
})
console.log("代碼執行結束");

1.執行整個代碼,遇到ajax異步操作
2.ajax進入Event Table,注冊回調函數success。
3.執行console.log("代碼執行結束")。
4.執行ajax異步操作
5.ajax事件完成,回調函數success進入Event Queue。
5.主線程從Event Queue讀取回調函數success并執行。

普通微任務宏任務實例
setTimeout(function(){
    console.log("定時器開始啦")
});

new Promise(function(resolve){
    console.log("馬上執行for循環啦");
    for(var i = 0; i < 10000; i++){
        i == 99 && resolve();
    }
}).then(function(){
    console.log("執行then函數啦")
});

console.log("代碼執行結束");

1.整段代碼作為宏任務執行,遇到setTimeout宏任務分配到宏任務Event Queue中
2.遇到promise內部為同步方法直接執行-“馬上執行for循環啦”
3.注冊then回調到Eventqueen
4.主代碼宏任務執行完畢-“代碼執行結束”
5.主代碼宏任務結束被monitoring process進程監聽到,主任務執行Event Queue的微任務
6.微任務執行完畢-“執行then函數啦”
7.執行宏任務console.log("定時器開始啦")

地獄模式:promise和settimeout事件循環實例
console.log("1");
// 1 6 7 2 4 5 9 10 11 8 3
// 記作 set1
setTimeout(function () {
    console.log("2");
    // set4
    setTimeout(function() {
        console.log("3");
    });
    // pro2
    new Promise(function (resolve) {
        console.log("4");
        resolve();
    }).then(function () {
        console.log("5")
    })
})

// 記作 pro1
new Promise(function (resolve) {
    console.log("6");
    resolve();
}).then(function () {
    console.log("7");
    // set3
    setTimeout(function() {
        console.log("8");
    });
})

// 記作 set2
setTimeout(function () {
    console.log("9");
    // 記作 pro3
    new Promise(function (resolve) {
        console.log("10");
        resolve();
    }).then(function () {
        console.log("11");
    })
})
第一輪事件循環

1.整體script作為第一個宏任務進入主線程,遇到console.log,輸出1。

2.遇到set1,其回調函數被分發到宏任務Event Queue中。

3.遇到pro1,new Promise直接執行,輸出6。then被分發到微任務Event Queue中。

4.遇到了set2,其回調函數被分發到宏任務Event Queue中。

主線程的整段js代碼(宏任務)執行完,開始清空所有微任務;主線程執行微任務pro1,輸出7;遇到set3,注冊回調函數。

第二輪事件循環

1.主線程執行隊列中第一個宏任務set1,輸出2;代碼中遇到了set4,注冊回調;又遇到了pro2,new promise()直接執行輸出4,并注冊回調;

2.set1宏任務執行完畢,開始清空微任務,主線程執行微任務pro2,輸出5。

第三輪事件循環

1.主線程執行隊列中第一個宏任務set2,輸出9;代碼中遇到了pro3,new promise()直接輸出10,并注冊回調;

2.set2宏任務執行完畢,開始情況微任務,主線程執行微任務pro3,輸出11。

類似循環...

所以最后輸出結果為1、6、7、2、4、5、9、10、11、8、3。

參考文章

https://www.cnblogs.com/Mainz...

http://www.ruanyifeng.com/blo...

https://juejin.im/post/5b4dfb...

https://juejin.im/post/5b879a...

https://juejin.im/post/59e85e...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/54175.html

相關文章

  • 深入前端-徹底搞懂JS運行機制

    摘要:瀏覽器是多進程的詳情看我上篇總結瀏覽器執行機制的文章深入前端徹底搞懂瀏覽器運行機制瀏覽器每打開一個標簽頁,就相當于創建了一個獨立的瀏覽器進程。執行異步操作事件完成,回調函數進入。主線程從讀取回調函數并執行。 最近看了很多關于JS運行機制的文章,每篇都獲益匪淺,但各有不同,所以在這里對這幾篇文章里說的很精辟的地方做一個總結,參考文章鏈接見最后。本文博客地址 了解進程和線程 進程是應用...

    jaysun 評論0 收藏0
  • 深入前端-徹底搞懂瀏覽器運行機制

    摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協調、主控),只有一個。 負...

    YPHP 評論0 收藏0
  • 深入前端-徹底搞懂瀏覽器運行機制

    摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協調、主控),只有一個。 負...

    Youngs 評論0 收藏0
  • 徹底搞懂瀏覽器Event-loop

    摘要:檢查宏任務隊列,發現有的回調函數立即執行回調函數輸出。接著遇到它的作用是在后將回調函數放到宏任務隊列中這個任務在再下一次的事件循環中執行。 為什么會寫這篇博文呢? 前段時間,和頭條的小伙伴聊天問頭條面試前端會問哪些問題,他稱如果是他面試的話,event-loop肯定是要問的。那天聊了蠻多,event-loop算是給我留下了很深的印象,原因很簡單,因為之前我從未深入了解過,如果是面試的時...

    source 評論0 收藏0
  • 一篇文章徹底搞懂JS深淺拷貝和const

    摘要:圖數據類型圖引用類型深淺拷貝問題不知道什么是深拷貝和淺拷貝的請先去并在調試臺自己操作一下,這篇文章只會說明為何中會有這種問題。所以有的時候我們為了避免淺拷貝,會用一些方式實現深拷貝。 首先要了解的js基礎 基本數據類型:Object、undefined、null、Boolean、Number、String、Symbol (ES6新加) Object包括: Array 、Date 、R...

    MyFaith 評論0 收藏0

發表評論

0條評論

luckyw

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<