???目錄???
- 🔄事件回圈🔄
- 🔞JavaScript代碼執行順序🈲
- 🔴IO阻塞和🟢非阻塞,👣同步和🦿異步的區別
🔄事件回圈🔄
事件回圈可以理解為我們撰寫的JavaScript代碼和瀏覽器或者node之間的橋梁,橋梁之間他們通過回呼函式進行溝通,無論是我們的檔案IO,資料庫操作,定時器,子行程,在完成對應的操作之后都會將結果和回呼函式放到事件回圈(任務佇列)中去,事件回圈會不斷的從任務對列中取出對應的事件(回呼函式)放入函式的呼叫堆疊中執行,

比如說JavaScript執行一個檔案讀寫的操作,但是JavaScript不具備檔案讀寫功能,就會通過v8引擎翻譯后去呼叫node.js bindings的庫,然后進入到libuv中,libuv再去連接作業系統對檔案進行讀寫,回傳結果時worker threads將系統呼叫的結果放入到事件佇列中,再通過事件回圈傳入到JavaScript端,讓回呼函式執行
🔞JavaScript代碼執行順序🈲
事件回圈其實維護著兩個佇列,一個微任務(promise的then和catch,queueMicrotask()等)佇列,一個宏任務(dom監聽,ajax請求,setInterval,setTimeout等)佇列,具體執行順序如下
- 函式的呼叫堆疊,JavaScript是單執行緒從上往下執行,先進堆疊的后出堆疊,堆疊中函式執行完畢全部彈出才會執行微佇列和宏佇列
console.log('log')
function sum() {
console.log('sum')
}
function foo() {
sum()
console.log('foo')
}
foo();
//log
//sum
//foo
- 堆疊的規則是先進后出,按理說最先壓入堆疊的是console.log(‘log’)(console也是函式),會在堆疊底,最后才會被呼叫執行,但是為什么卻先執行呢?
- 因為consloe.log(‘log’)只有一個列印操作,一執行就結束了,執行結束就會彈出堆疊,
- 而在執行foo函式(壓堆疊)的時候,還沒執行完又呼叫了sum函式,就會又將sum函式壓入堆疊中,按照后進先出的規則sum函式后進堆疊則先出堆疊,最后foo函式執行完畢彈出
- 微任務佇列,呼叫堆疊中函式執行完畢之后,微佇列中的任務入堆疊
- 當微佇列為空之后,宏佇列中的任務入堆疊
const message = '優先執行1'
console.log(message)
setTimeout(() => {
console.log("宏佇列最后執行")
})
new Promise(function(resolve) {
resolve();
console.log('優先執行2')
}).then(function() {
console.log("微佇列后執行");
});
// 優先執行1
// 優先執行2
// 微佇列后執行
// 宏佇列最后執行

🔴IO阻塞和🟢非阻塞,👣同步和🦿異步的區別
1??阻塞和非阻塞是相對于被調方用來說的(也就是作業系統),作業系統提供了兩種呼叫方式,呼叫時可以隨意選取阻塞式呼叫還是非阻塞式呼叫
- 阻塞式呼叫
操作檔案時,呼叫結果回傳之前當前執行緒處于阻塞態(阻塞態時cpu是不會分配時間片的),執行緒只會在得到呼叫結果之后才會回到就緒態得到時間片繼續執行 - 非阻塞式呼叫
操作檔案時,呼叫執行后當前執行緒不會停止執行,只需要過一段時間來檢查一下有沒有回傳結果(因為此時前面的未執行完,沒有完全拿到回傳結果)
雖然看著非阻塞式IO相對阻塞IO不會產生堵塞的情況,但是也有一些問題——需要頻繁的去確定是否已經獲取到了全部的資料,不斷的確定的程序稱為輪詢,只有完全獲取到資料后才能傳給程式做相關的處理,
在node.js中的libuv中提供了一個執行緒池,會負責相關的操作,通過輪訓或者其他方式等待結果,當執行緒池呼叫某個執行緒完成輪訓操作后,會通過事件回圈將本次得到的資料和之前注冊的回呼函式放到某個事件佇列里面,然后進入函式的呼叫堆疊執行
2??同步和異步是相對于呼叫方來說的,
- 如果發起呼叫后不會進行其他任何操作,只是等待結果,這個程序就是同步呼叫,
- 如果發起呼叫之后并不會等待結果,繼續完成后續的作業,等到有回呼了之后再去執行,這個程序就是異步呼叫
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/289888.html
標籤:其他
