日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JS引擎(The JAVAScript Engine)

JavaScript引擎的一個流行示例是google的V8引擎。V8引擎被用在了Chrome和Nodejs里。

JS中的事件循環和任務隊列

 

運行時(The Runtime)

瀏覽器中有很多幾乎每個開發都調用過的API,比如 setTimeout等,但引擎不提供這些API。

JS中的事件循環和任務隊列

 

JS是單線程的并發語言,這就意味著,在一個時間段內,它只能處理一項任務或執行一段代碼。它有一個單一的調用棧(Single Call Stack),和堆(Heap),隊列(Queue)組成的JS并發模型(Javascript Concurrentcy Model).

JS中的事件循環和任務隊列

 

[可視化表示]

1. 調用棧(Call Stack): 在程序中,它是一個記錄程序調用的數據結構。每個數據結構,也可稱為棧幀。

來看一下MDN上的例子:

function foo(b) {
  var a = 5;
  return a * b + 10;
}

function bar(x) {
  var y = 3;
  return foo(x * y);
}

console.log(bar(6)); // 返回 100

當調用 bar 時,創建了第一個幀 ,幀中包含了 bar 的參數和局部變量。當 bar 調用 foo 時,第二個幀就被創建,并被壓到第一個幀之上,幀中包含了 foo 的參數和局部變量。當 foo 返回時,最上層的幀就被彈出棧(剩下 bar 函數的調用幀 )。當 bar 返回的時候,棧就空了。

再加一張動態圖:

JS中的事件循環和任務隊列

 

我們有時會在瀏覽器的控制臺看到長長的紅色錯誤堆棧跟蹤,它基本上指示了當前調用堆棧的狀態,以及該函數在堆棧中從上到下失敗的方式。

function foo(){
throw new Error("Oops!");
}
function bar(){
    foo();
}
function baz() {
    bar();
}
baz();
JS中的事件循環和任務隊列

 

[Chrome瀏覽器]

有時,我們進入函數的無限循環,也會拋出錯誤。在Chrome中,棧里的最大深度為16,000。

JS中的事件循環和任務隊列

 

2.堆(Heap):對象被分配在一個堆中,即用以表示一大塊非結構化的內存區域。

3.隊列(Queue):一個 JavaScript 運行時包含了一個待處理的消息隊列。每一個消息都關聯著一個用以處理這個消息的函數。

在事件循環期間的某個時刻,運行時從最先進入隊列的消息開始處理隊列中的消息。為此,這個消息會被移出隊列,并作為輸入參數調用與之關聯的函數。正如前面所提到的,調用一個函數總是會為其創造一個新的棧幀。

函數的處理會一直進行到執行棧再次為空為止;然后事件循環將會處理隊列中的下一個消息(如果還有的話)。

Event Loop

基本上,當我們評估 JS 代碼的性能時,堆棧中的函數會使其速度慢或快,但執行d成千上萬次迭代,或使用或執行超過數百萬行代碼的文件,速度將變慢,而且會保持堆棧占用或阻止。這樣的代碼或文件稱為阻止腳本(Blocking script).

網絡請求可能很慢,圖片請求可能很慢,但幸運的是,服務器請求可以通過 AJAX(異步函數)來完成。我們假設,這些網絡請求是通過同步函數進行的,那么會發生什么?網絡請求發送到某些服務器,不能就是另一臺在某處的計算機?,F在,計算機發送回響應的速度可能會很慢。同時,如果我單擊某個 CTA 按鈕,或者需要執行一些其他渲染,則堆棧被阻止時不會執行任何操作。在多線程語言(如 Ruby)中,可以處理它,但在 Javascript 等單線程語言中,除非堆棧中的函數返回值,否則這是不可能的。網頁將崩潰,因為瀏覽器不能做任何事情。如果我們想要最終用戶的流暢 UI,這不是理想的選擇。我們如何處理?

最簡單的解決方案是使用異步回調,這意味著我們運行代碼的某些部分,并給它一個回調(函數),稍后將被執行。我們都一定遇到異步回調,就像使用Node的任何AJAX請求一樣,都是關于異步函數執行的。所有這些異步回調不會立即運行,將會在稍后運行,因此不能立即推送到堆棧內,不像同步函數,如它們到底去哪里,它們如何處理? $.get(),setTimeout(),setInterval(), Promises, etc. `console.log(), mathematical operations.`

JS中的事件循環和任務隊列

 

從上圖中,網絡請求在執行過程:

1、請求函數被執行,傳遞一個匿名函數作為回調,這個函數在將來某個時候,當響應(response)可用時執行。

2、“Script call done!” 被立即輸出到控制臺。

3、在將來某時刻,響應(response)從服務端返回,執行我們的回調函數,并將其body輸出到控制臺。

調用方與響應的解耦使JavaScript運行時可以在等待異步操作完成并觸發其回調前執行其他操作。在瀏覽器中,用于處理異步事件,是由C++來實現的,例如DOM事件,http請求,setTimeout等(知道了這一點之后,在Angular 2中,使用了區域,這些區域對這些API進行了猴子修補,以引起運行時更改檢測,現在我可以了解它們如何實現此目的。)在瀏覽器中,當這些API被調用時,瀏覽器將創建進程處理異步的回調函數。

瀏覽器Web API-由瀏覽器創建的線程,使用C ++實現,用于處理異步事件,例如DOM事件,http請求,setTimeout等。

由于這些WebAPI本身不能將執行代碼放到堆棧上,如果這樣做了,它將隨機出現在代碼中間。由于這些WebAPI本身不能將執行代碼放到堆棧上,如果這樣做了,它將隨機出現在代碼中間。 上面討論的消息回調隊列展現了方法。 任何WebAPI在執行完,都會將回調(function)推送到此隊列中?,F在,事件循環(Event Loop)負責在 隊列(Queue) 中執行這些回調,并在其為空時將其壓入 堆棧(Stack) 。

進入隊列,并不會立即被執行,只有當前Event Loop執行棧中的任務被執行完成后,才會被壓入執行棧。

事件循環(Event Loop)的基本工作是同時查看堆棧(Stack)和任務隊列(Queue),并在將堆棧視為空時將隊列中的第一件事推入堆棧。 在處理任何其他消息之前,將完全處理每個消息或回調。

while (queue.waitForMessage()) {  
queue.processNextMessage();  
}
JS中的事件循環和任務隊列

 

在 Web 瀏覽器中,每當發生事件(Event)并附加事件偵聽器(Listener)時,都將添加消息(Message)。如果沒有偵聽器(Listener),則事件(Event)將丟失。因此,單擊具有 click 事件處理程序的元素(Element)將添加一條消息(Message) - 與任何其他事件一樣。此回調函數(Callback function)的調用將用作調用堆棧中的初始幀,由于 JavaScript 是單線程的,在堆棧上返回所有調用之前,將停止進一步的消息輪詢和處理。后續(同步)函數調用向堆棧添加新的調用幀。

現在可以看出,有很多不同的任務隊列,由上面可知,一般可分為兩類,1)宏任務,2)微任務。

隊列優先級

我先把結論COPY過來,有時間再寫一篇文章詳細說明。

小結

在JS引擎中,我們可以按性質把任務分為兩類,macrotask(宏任務)和 microtask(微任務)。

瀏覽器JS引擎中:

macrotask(按優先級順序排列): script(你的全部JS代碼,“同步代碼”), setTimeout, setInterval, setImmediate, I/O,UI rendering

microtask(按優先級順序排列):process.nextTick,Promises(這里指瀏覽器原生實現的 Promise), Object.observe, MutationObserver

JS引擎首先從macrotask queue中取出第一個任務,執行完畢后,將microtask queue中的所有任務取出,按順序全部執行;

然后再從macrotask queue(宏任務隊列)中取下一個,執行完畢后,再次將microtask queue(微任務隊列)中的全部取出;

循環往復,直到兩個queue中的任務都取完。

所以,瀏覽器環境中,js執行任務的流程是這樣的:

第一個事件循環,先執行script中的所有同步代碼(即 macrotask 中的第一項任務)

再取出 microtask 中的全部任務執行(先清空process.nextTick隊列,再清空promise.then隊列)

下一個事件循環,再回到 macrotask 取其中的下一項任務

再重復2

反復執行事件循環…

NodeJS引擎中:

先執行script中的所有同步代碼,過程中把所有異步任務壓進它們各自的隊列(假設維護有process.nextTick隊列、promise.then隊列、setTimeout隊列、setImmediate隊列等4個隊列)

按照優先級(process.nextTick > promise.then > setTimeout > setImmediate),選定一個 不為空 的任務隊列,按先進先出的順序,依次執行所有任務,執行過程中新產生的異步任務繼續壓進各自的隊列尾,直到被選定的任務隊列清空。

重復2...

也就是說,NodeJS引擎中,每清空一個任務隊列后,都會重新按照優先級來選擇一個任務隊列來清空,直到所有任務隊列被清空。

分享到:
標簽:JS
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定