摘要:同步異步是單線程的,每次只能做一件事情。像以下這種情況,代碼會按順序執行,這個就叫同步。雖然是單線程,但是瀏覽器是多線程的,在遇到像事件等這種任務時,會轉交給瀏覽器的其他工作線程上面提到的幾個線程執行,執行完之后將回調函數放入到任務隊列。
同步、異步
JS是單線程的,每次只能做一件事情。像以下這種情況,代碼會按順序執行,這個就叫同步。
console.log(1); console.log(2); console.log(3);
以下代碼會輸出2、3、1,像這種不按順序執行的,或者說代碼執行中間有時間間隙的,叫異步。
setTimeout(() => { console.log(1); }, 0); console.log(2); console.log(3);事件循環
一個瀏覽器通常有以下幾個常駐的線程:
渲染引擎線程:該線程負責頁面的渲染
JS引擎線程:負責JS的解析和執行
定時觸發器線程:處理定時事件,比如setTimeout, setInterval
事件觸發線程:處理DOM事件
異步http請求線程:處理http請求
渲染線程和JS引擎線程是不能同時進行的。也就是說在執行代碼時,渲染會掛起;渲染DOM時,代碼也不會執行。
雖然JS是單線程,但是瀏覽器是多線程的,在遇到像setTimeout、DOM事件、ajax等這種任務時,會轉交給瀏覽器的其他工作線程(上面提到的幾個線程)執行,執行完之后將回調函數放入到任務隊列。
在JS運行環境里,除了主線程外,還有任務隊列。
// eventLoop是一個用作隊列的數組 // (先進,先出) var eventLoop = [ ]; var event; // “永遠”執行 while (true) { // 一次tick if (eventLoop.length > 0) { // 拿到隊列中的下一個事件 event = eventLoop.shift(); // 現在,執行下一個事件 event(); } }
我們可以用上面的代碼來想像一下JS的執行情況。
JS主線程,就像是一個while循環,會一直執行下去。在這期間,每次都會查看任務隊列有沒有需要執行的任務(回調函數)。在執行完一個任務之后,會繼續下一個循環,直到任務隊列所有任務都執行完為止。
任務隊列又分微任務隊列和宏任務隊列
微任務Promise
MutationObserver
Object.observe()(已廢棄)
宏任務setTimeout
setInterval
setImmediate
IO
UI rendering(DOM event)
執行過程在JS執行完同步任務之后,會開始執行微任務隊列
在將所有的微任務執行完之后,會開始執行宏任務隊列
在執行完一個宏任務之后,跳出來,重新開始下一個循環(從1開始執行)
也就是說執行微任務隊列 會將隊列中的所有微任務執行完 而執行宏任務隊列 每次只執行一個宏任務 然后重新開始下一個循環
我們可以看看以下代碼
setTimeout(() => { console.log(3) new Promise((resolve, reject) => { console.log(5) resolve() }).then(console.log(6)) }, 0) setTimeout(() => { console.log(4) }, 0) new Promise((resolve, reject) => { console.log(1) resolve() }).then(console.log(2))
輸出是1 2 3 5 6 4
我們來分析一下代碼的執行過程
前面的兩個setTimeout都是宏任務,所以現在宏任務隊列有2個任務
Promise里面的代碼是同步任務,所以現在會馬上執行 輸出1
Promise的then是微任務,所以現在微任務隊列有1個任務
在執行完同步任務之后,開始執行微任務,也就是console.log(2), 輸出2
在執行完微任務之后,會執行宏任務,第一個宏任務也就是第一個setTimeout
第一個setTimeout會先輸出3,然后輸出5,因為這兩個都是同步任務,然后遇到then,加入微任務隊列,宏任務執行完重新開始下一個循環。
因為沒有同步代碼,所以接著執行微任務,此時微任務隊列有1個任務(第6步加入), 宏任務隊列還有1個任務(第6步執行完了第一個宏任務)
執行微任務,輸出6
再執行宏任務,輸出4
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100395.html
摘要:回調函數,一般在同步情境下是最后執行的,而在異步情境下有可能不執行,因為事件沒有被觸發或者條件不滿足。同步方式請求異步同步請求當請求開始發送時,瀏覽器事件線程通知主線程,讓線程發送數據請求,主線程收到 一直以來都知道JavaScript是一門單線程語言,在筆試過程中不斷的遇到一些輸出結果的問題,考量的是對異步編程掌握情況。一般被問到異步的時候腦子里第一反應就是Ajax,setTimse...
摘要:函數會在之后的某個時刻觸發事件定時器。事件循環中的這樣一次遍歷被稱為一個。執行完畢并出棧。當定時器過期,宿主環境會把回調函數添加至事件循環隊列中,然后,在未來的某個取出并執行該事件。 原文請查閱這里,略有改動。 本系列持續更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現在,我們將會通過回顧單線程環境下編程的弊端及如何克服這些困難以創建令人驚嘆...
摘要:事件循環事件循環是指主線程重復從消息隊列中取消息執行的過程。事件觸發時,表示異步任務完成,會將事件監聽器函數封裝成一條消息放到消息隊列中,等待主線程執行。 一. 單線程 我們常說JavaScript是單線程的。 所謂單線程,是指在JS引擎中負責解釋和執行JavaScript代碼的線程只有一個。不妨叫它主線程。 但是實際上還存在其他的線程。例如:處理AJAX請求的線程、處理DOM事件的線...
摘要:當主線程開始執行異步任務,實際就是執行對應的回調函數。異步任務必須指定回調函數。所以注意的是,只是將事件插入了任務隊列,必須等到當前代碼執行棧執行完,主線程才會去執行它指定的回調函數。 最近本人對于js的運行機制,特別是異步,還有回調函數感覺很亂,于是參考了很多有用的博客(博客原文地址會在文末給出),整理如下: js單線程 我們都知道,Javascript語言的執行環境是單線程(si...
閱讀 1781·2021-11-11 11:02
閱讀 1687·2021-09-22 15:55
閱讀 2492·2021-09-22 15:18
閱讀 3492·2019-08-29 11:26
閱讀 3749·2019-08-26 13:43
閱讀 2651·2019-08-26 13:32
閱讀 906·2019-08-26 10:55
閱讀 969·2019-08-26 10:27