js 事件迴圈

2022-07-09 19:42:11 字數 2743 閱讀 7926

js執行的環境稱之為宿主環境。

執行棧 :call stack ,乙個資料結構,用於存放各種函式的執行環境,每乙個函式執行之前他的相關資訊會加入到執行棧中,函式呼叫之前,建立執行環境,然後加入到執行棧中;函式呼叫之後,銷毀執行環境

function a ()

function b()

function c()

console.log("global")

a()

執行順序: global  a  b  c  

答案顯而易見,但是為什麼會這樣呢?

整個js執行了之後 就只有乙個執行棧,首先整個js定義了三個函式,js**在執行的時候都會先初始化乙個全域性上下文go,然後把go放入在call stack 中,接著console.log()函式執行,建立乙個log的上下文放入call stack,輸入「global」之後log的上下文就會銷毀,然後a()函式執行,建立乙個a的上下文放入call stack,輸出"a",b()執行,這時a函式還沒有結束,因為a函式裡面還需要執行b函式,所以a的上下文還留在call stack中,b() 函式執行,建立乙個b的執行上下文放入call stack 中,b函式出入"b",c(),這時b函式也還沒有結束,還需要執行c()函式,所以b的上下文也還在call stack中沒有銷毀,c()函式執行,建立乙個c的上下文放入到call stack中,c函式輸出"c"後,c函式結束,call stack裡面的c的上下文銷毀,c函式執行完,b函式也就執行完了所以,接著,b的上下文也接著銷毀,b函式執行完後a函式也就代表著執行完,所以a的上下文也接著被銷毀,最後這整個js**執行完後call stack裡面最先初始化建立的全域性上下文就銷毀。

再來乙個例子鞏固一下上面的原理:求斐波拉契數列 第乙個和第二個數固定為1,之後任意乙個數都是前兩位數之和

function getfeibo(n)

return getfeibo(n-1) + getfeibo(n-2)

}console.log(getfeibo(3))

首先初始化乙個全域性上下文放入call stack 中 log()執行 建立乙個log的執行上下文放入call stack 中 這時getfeibo(3)執行,建立乙個n=3的getfeibo的執行上下文,n=3沒有進入if語句,執行getfeibo(3-1)函式,建立乙個n=2 的getfeibo的執行上下文,進入if語句 返回1,n=2的getfeibo的執行上下文銷毀,return的前部分結束,執行 getfeibo(3-2)函式,建立乙個 n=1 的getfeibo的執行上下文, 進入if語句,返回1,n=1的getfeibo的執行上下文銷毀,return的後部分結束 n=3的getfeibo函式執行結束返回2 ,n=3的getfeibo的執行上下文銷毀,最後初始化的那個全域性上下文也銷毀這時call stack清空。

js引擎永遠執行的都是執行棧的最頂部

非同步函式:某些函式不會立即執行,需要等到某個時機到達後才會執行,這樣的函式就被稱之為非同步函式,比如時間處理函式。非同步函式的執行時機,會被宿主環境控制。

瀏覽器宿主環境中包含有5個執行緒:

js引擎:負責執行執行棧的最頂部**

gui執行緒:負責渲染頁面

事件監聽執行緒:負責監聽各種事件

計時執行緒:負責計時(settimeout、setinterval)

網路執行緒:負責網路通訊 如 ajax

當上面的執行緒發生了某些事情,如果該執行緒發現,這件事情有處理程式,他就會將該處理程式放入到乙個叫做事件佇列的的記憶體裡,當js引擎發現,執行棧call stack 中裡面已經沒有任何內容後,call stack就會把事件佇列中的第乙個函式加入到執行棧中去執行

例如:

function a(),0)

c()}

function b()

function c()

console.log("global")

a()

輸出順序:global a c b

首先初始化乙個全域性執行上下午放入call stack中 log()函式執行,建立乙個log的執行上下文,輸出global,log的執行上下文銷毀,a函式執行,建立乙個a的執行上下文,log執行建立乙個log的執行上下文,輸出a,log的執行上下文銷毀,settimeout 開啟乙個定時器告訴宿主環境0秒後執行b函式,注意這時b函式還沒有執行,就緊接著執行c函式

建立乙個c的執行上下文,log執行建立乙個log的執行上下文,輸出c,log的執行上下文銷毀,這時a函式裡面的**執行完 a的執行上下文被銷毀,整個js**執行完畢,全域性上下文也從call stack被銷毀,call stack清空。這時有人會問 誒 b函式不是還沒有執行嗎怎麼說整個js**執行完畢了呢? 是這樣的 settimeout開啟了乙個定時器,這時已經是計時執行緒發現了有處理程式,會告訴宿主環境 0 秒後執行b函式,宿主環境知道後就會在0秒過後把 b函式放入到乙個叫事件佇列的記憶體中。所以當call stack 裡面的內容清空後(即當最開始初始化的全域性上下文被銷毀後)js引擎會從事件佇列中取出處理程式來執行。

js引擎從事件佇列中取出處理程式來執行,以及與宿主環境的配合,稱之為事件迴圈

事件佇列在不同的宿主環境中有所差異,大部分宿主環境會將事件佇列進行細分。在瀏覽器中,事件佇列被分為兩種:

巨集佇列:macrotask,計時器結束的**、事件**、http**等等絕大部分非同步函式是進入巨集佇列

微佇列:mutationobserver,promise產生的**進入微佇列

當執行棧清空是,js引擎首先會將微任務中的所有任務一次執行結束,如果沒有微任務,則執行巨集任務。

JS 迴圈設定事件

input type radio name attr value 1 id attr1 label for attr1 rmb br input type radio name attr value 2 id attr2 label for attr2 my br input type radio ...

JS迴圈新增事件

for var t 0 t ischeckname.length t var importgoodslisttr new array 插入行 alert new date for var n 0 n大家注意紅色字型的內容 將需要迴圈新增事件的物件的value設定為迴圈變數n,此時如何操作其它的陣列物...

js事件迴圈機制

1 所有同步任務都在主線程上執行,形成乙個執行棧 execution context stack 2 主線程之外,還存在乙個 任務佇列 task queue 只要非同步任務有了執行結果,就在 任務佇列 之中放置乙個事件。3 一旦 執行棧 中的所有同步任務執行完畢,系統就會讀取 任務佇列 看看裡面有哪...