1. 程式人生 > >【JavaScript 學習--12】JS深入理解呼叫棧,事件迴圈機制,回撥佇列

【JavaScript 學習--12】JS深入理解呼叫棧,事件迴圈機制,回撥佇列

最近研究JavaScript裡的函式事件這些到底是如何呼叫的,查閱了好些資料,特別是國外一些大牛寫的文章,啟發非常的大,於是打算對這些知識進行梳理。

基本知識

  • JS是什麼?
    • JS是單執行緒,非阻塞,非同步,併發的語言
    • JS有 呼叫棧,事件迴圈,回撥佇列,其它的APIs。
  • JS 在執行時
    • JS在執行時(像V8引擎)有堆(記憶體分配)和棧(執行環境), 但是他們沒有 setTimeout, DOC 等,這些是瀏覽器的web APIs。
  • 我們知道的JS在瀏覽器裡有:
    • 執行時的V8(堆/棧)
    • 瀏覽器提供web APIs,比如DOM, ajax, 和setTimeout
    • 事件的回撥佇列,比如onClick, onLoad, onDone。
    • 事件迴圈
      這裡寫圖片描述
  • JS的單執行緒(single thread):僅僅是指JS程式碼執行在單執行緒裡面。
  • 呼叫棧(call stack):又稱執行環境(execution contexts), 當函式或者程式呼叫的時候,就把該函式push到呼叫棧,結束時候,就從棧頂端移除。遵循FILO(先進後出)原則。注意:呼叫棧有個最大呼叫幀,chrome 瀏覽器最大支援16000個呼叫幀,超過後,會報“RangeError:Maximum call stack size exceeded”
  • 堆(Heap): 記憶體分配(memory allocation)的一塊空間。JS的引用型別的值是放在堆記憶體的。
  • 回撥佇列(callback Queue)
    :JS在執行時候,有一個列表用於記錄將要處理的回撥事件。遵循FIFO(先進先出)原則。
  • 事件迴圈(event loop): 事件迴圈不斷的輪詢檢測呼叫棧是否為空?如果不為空,就等待呼叫棧為空,否則就把回撥佇列列表裡的事件放到呼叫棧執行。迴圈直到回撥佇列列表為空。

同步函式呼叫棧機制

我們以一個例子來進行同步函式執行的機制, 有兩個函式foo,和bar,bar內部呼叫foo。

function foo(a, b) {
console.log("in foo");
return a * b;
}

function bar(y) {
var x = 10;
console.log("in bar"
); return foo(x, y); } console.log(bar(5));

以上程式碼執行順序如下:

  1. 最先進入console.log(bar(5)); 因此它被推送到呼叫棧。
  2. console.log(bar(5));呼叫函式bar(5), 等待bar(5)的返回結果,於是把bar(5)推送到呼叫棧頂部。
  3. 函式bar(5)裡有console.log("in bar");於是推送console.log("in bar");到棧頂。
  4. console.log("in bar");執行完成返回,然後將console.log("in bar");從棧頂移除。
  5. 接著執行return foo(x, y);,這是呼叫foo(x, y),把foo(x, y)推入到呼叫棧。
  6. 執行console.log("in foo");推入棧頂,結束,移除棧。
  7. 執行return a * b; 呼叫 a * b,推送a * b到棧頂,a * b執行完後,出棧。
  8. 接著 return 10+5的結果返回給bar函式的foo(10, 5),這樣foo(x,y)函式結束執行,foo(x,y)從呼叫棧移除。
  9. 接著bar(y)函式return foo(10, 5)的值給bar(5),這樣bar(5)執行結束,從呼叫棧中移除。
  10. 最後console.log(bar(5));打印出15值,console.log呼叫完成,將console.log移除棧。這時呼叫棧就為空了,呼叫結束。
    執行順序請參考下圖:
    同步函式執行機制

非同步呼叫的事件迴圈機制

我們以setTimeout 為例, 有這樣程式碼,用兩個不同的timeout來闡述setTimeout的事件迴圈機制。

console.log("1");

setTimeout(function secondTimeout() {
    console.log("2");
}, 5000);

setTimeout(function firstTimeout() {
    console.log("3");
}, 0);
console.log("4.");

以上程式碼執行後列印順序是: 1, 4, 3, 2
以上程式碼執行機制如下:
1. 程式碼執行的console.log("1");將其push到呼叫棧,緊接著完成,從呼叫棧刪除
這裡寫圖片描述
2. 接著呼叫setTimeout的secondTimeout,將其push到呼叫棧,由於setTimeout是web API,因此web API 處理secondTimeout這個事件,並從呼叫棧中移除,並且在web API中開始等待5秒。
這裡寫圖片描述
3. 接著呼叫setTimeout的firstTimeout,將其push到呼叫棧,由於setTimeout是web API,因此web API 處理這個firstTimeout事件, 由於等待是0秒,於是將firstTimeout推送到回撥佇列,等待呼叫棧的執行(遵循先進先出原則)。這時事件迴圈(event loop)機制開始執行,檢查這時呼叫棧不為空?繼續排隊等待:把回撥佇列列表的第一個佇列推送到呼叫棧執行。由於此時,呼叫棧還要繼續執行console.log("4.");所以繼續等待呼叫棧結束。
這裡寫圖片描述
4. 接著console.log("4.");列印完成,這時已經是到程式碼執行尾部,沒有主程式碼運行了,呼叫棧為空。事件迴圈機制檢查到呼叫棧為空後,將第一個在callback Queue裡的函式firstTimout() 推送到呼叫棧執行,並呼叫console.log(3)。結束後釋放呼叫棧。
這裡寫圖片描述
5. 當此時呼叫棧為空時,event loop繼續將callback Queue例表裡的其他佇列一個一個push到呼叫棧去執行。如果此時回撥佇列例表裡有多個佇列排隊,那麼就安裝此迴圈,直到全部完成為止。
這裡寫圖片描述

promise的事件迴圈機制

參考資料

相關推薦

JavaScript 學習--12JS深入理解呼叫事件迴圈機制佇列

最近研究JavaScript裡的函式事件這些到底是如何呼叫的,查閱了好些資料,特別是國外一些大牛寫的文章,啟發非常的大,於是打算對這些知識進行梳理。 基本知識 JS是什麼? JS是單執行緒,非阻塞,非同步,併發的語言 JS有 呼叫棧,事件迴圈,回撥

JavaScript 學習--05Nodejs之如何呼叫 cmd 命令

/*For getting data from PR system API*/ var express = require('express'); var router = express.Rout

Javascript學習筆記js執行緒實戰— —實現隨機速度的打字機效果

目錄 隨機速度的打字機效果 效果 程式碼 html部分 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF

JavaScript學習筆記1:js的書寫,顯示資料,變數,函式

JavaScript描述的是網頁的行為,可以直接改變HTML而改變網頁的內容,或者提供和使用者的互動。 js寫在哪裡 ①直接寫入HTML JavaScript可以寫在HTML的script雙標籤裡,一般把這個雙標籤放在HEAD頭裡: <

JavaScript學習筆記if使用

document asc cnblogs class body 學習筆記 lang div var <html> <body> <script language="JavaScript">

JavaScript學習筆記鼠標樣式

右箭頭 javascrip script mov wait bsp cursor and ossh style="cursor:hand" 手形 style="cursor:crosshair" 十字形 style="cursor:text" 文本

JavaScript學習筆記調用google搜索

alt href blog ddl ear input arch -c html <html> <form method=get action="http://www.google.com/search"> <a

JavaScript學習筆記畫圖

ctype net ner cli onmouseup move con cursor bsp <!DOCTYPE HTML> <html> <head> <script type="text/ja

JavaScript學習筆記hello world

div color html pre 學習筆記 bsp body pan class <html> <body> <script language="JavaScript"> al

JavaScript學習筆記點擊消失

hid his script click fun bsp logs document query <!DOCTYPE html> <html> <head> <script type="text/j

理解Javascript函式執行—呼叫事件迴圈、任務等

原文作者:Gaurav Pandvia 原文連結:medium.com/@gaurav.pan… 文中部分連結可能需要梯子。 歡迎批評指正。 現如今,web開發者(我們更喜歡被叫做前端工程師)用一門指令碼語言就能做任何事情,從提供瀏覽器中的互動,到開發電腦遊戲、桌面工具、跨平臺移動

Javascript學習筆記DOM實戰— —jQ實現點選任意位置關閉某處的效果(常用於模態框後面的遮罩層)

【Javascript學習筆記】 目錄 目錄 原理 效果 程式碼 實戰程式碼 快捷連結 點選任意位置關閉某處 而且點選對應處並不會hide掉自己 原理

MyBatis學習12MyBatis中的一級快取

  快取的作用是減輕資料庫的壓力,提高資料庫的效能的。mybatis中提供了一級快取和二級快取,先來看一下兩個快取的示意圖:   從圖中可以看出: 一級快取是SqlSession

redis 學習系列API的理解與使用

全局命令 時間復雜度 總數 鍵值 seconds clas mil height 同時 Redis提供了5種數據結構,以下介紹一些預備知識以及Redis的5種數據結構 1、預備知識 1.1 全局命令 Redis的5種數據結構,它們是鍵值對中的值,對於鍵來說有一些通用的

Java學習筆記66:認識Java中的Reflection(反射)機制,獲取類的屬性和方法

反射部分一直欠著,現在學框架和Servlet必須要學一下了。最近學習Struts2框架和Servlet時候,很多地方直接給出類名就可以去使用了,如在web.xml中配置Filter時: <filter> <filter-name&

JS-呼叫事件迴圈、訊息佇列(也叫任務隊和佇列)、作業佇列(微任務佇列

一:呼叫棧是個什麼鬼東西,它具有棧的屬性--後進先出 先看一段簡單的JS程式碼: const second = function(){ console.log('hello there'); } const first = function() { console.log('hi,first'); secon

JS瀏覽器賭博網站平臺出租事件迴圈機制

程序、執行緒程序賭博網站平臺出租【大神原始碼論壇】dsluntan.com  【布丁原始碼論壇】budingbbs.com 企娥3393756370是系統分配的獨立資源,是 CPU 資源分配的基本單位,程序是由一個或者多個執行緒組成的。執行緒是程序的執行流,是CPU排程和分派

Spark深入學習 -12Spark程序設計與企業級應用案例02

提升 算子 lin count() roi println groupby 工作問題 衍生 ----本節內容------- 1.遺留問題答疑 1.1 典型問題解答 1.2 知識點回顧 2.Spark編程基礎 2.1 Spark開發四部曲 2.2 RDD典型實例

Java深入理解Java虛擬機器」學習筆記(1) - Java語言發展趨勢

這本書寫的比較早,現在這些功能都已經不同程度的實現了。 1、模組化     JDK9之前的版本都是一個整體,使用者可能只需要使用一個小功能,但他不得不下載整個JDK。不能滿足定製化需求,顯然Java語言的發展因此大大受限。   所以,Sun公司在OpenJDK建立了一個Jigsaw(拼圖)的專案來推動模

Java深入理解Java虛擬機器」學習筆記(2)-記憶體管理

 一、執行時資料區   JVM在執行Java程式的時候,將其執行時資料區劃分為若干不同區域。它們的用途和建立及銷燬的時間不同。      1、程式計數器(Program Counter Register)     是一塊很小的記憶體空間。當執行緒執行的是Java方法,它記錄的是當前正在執行的