首先咱們你們都瞭解的是,JavaScript 是一門單線程語言,因此咱們就能夠得出:git
JavaScript 是按照語句順序執行的
首先看:github
let a = '1' console.log(a) let b = '2' console.log(b)
這個顯然你們都知道結果,依次輸出1,2瀏覽器
然而換一種:多線程
setTimeout(function() { console.log(1) }) new Promise(function(resolve) { console.log(2) for(var i = 0;i< 10;i++){ i === 10 && resolve() } }).then(function() { console.log(3) }) console.log(4)
這個時候再看代碼的順序執行,輸出1,2, 3, 4。好了放到瀏覽器運行一下,什麼?輸出竟然是 2, 4, 3,1。說好的按順序執行呢?下面就須要去了解一下 JavaScript 的執行機制問題了。異步
首先JavaScript 是一門單線程的語言,在最新的HTML5 推出的 Web-worker,可是 JavaScript 是一個單線程的語言這一個核心仍是沒有改變。因此,JavaScript 的多線程都是基於單線程模擬出來的。因此牢記 JavaScript 是單線程語言。函數
任務分爲兩類:線程
當咱們打開頁面時,頁面的渲染就是一大堆同步任務,而像加載圖片和音頻資源耗時的任務,就是異步任務。時間循環的主要內容就是:code
其中js引擎存在一個監控進程,不斷檢查主線程執行棧是否爲空,一旦爲空,就會去時間隊列那檢查有沒有等待被調用的函數。隊列
例如:進程
setTimeout( function() { console.log(1) }, 0) console.log(2)
這也就是爲何即便設置setTimeout(fn, 0)
函數也不會當即執行的緣由。不過即便主線程爲空,0ms也是達不到的,根據HTML標準,最低是4ms。
還有一個與setTimeout
相似的函數,對於setInterval
來講,是循環執行。對於執行順序來講,setInterval
會每隔指定的時間將註冊的函數置入Event Queue,若是前面的任務耗時過久,那麼一樣須要等待。
可是須要注意的一點是,對於setInterval(fn, ms)
來講,他並非每過ms
執行一次 ,而是每過 ms
會有fn
進入任務隊列。也就是說若是setInterval
的回調函數的執行事件若是超過延遲ms
,那麼就看不出來事件間隔了。
除了廣義的同步任務和異步任務以外,還有對任務更精細的劃分,分爲:
事件循環的順序,決定js代碼的執行順序。進入總體代碼(宏任務)後,開始第一次循環。接着執行全部的微任務。而後再次從宏任務開始,找到其中一個任務隊列執行完畢,再執行全部的微任務。
用一段代碼來講明:
setTimeout(function() { console.log('1'); }) new Promise(function(resolve) { console.log('2'); resolve() }).then(function() { console.log('3'); }) console.log('4');
setTimeout
,那麼它的回調函數進入到宏任務事件隊列中Promise
,Promise
當即執行,輸出2,then
任務進入到微任務事件隊列中then
,輸出3好了瞭解了基本的原理以後,咱們來看一個更復雜的:
console.log('1'); setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) process.nextTick(function() { console.log('6'); }) new Promise(function(resolve) { console.log('7'); resolve(); }).then(function() { console.log('8') }) setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') }) })
不知道你們答案是什麼?接下來咱們來進行分析一下:
第一輪:
console.log()
輸出1setTimeout()
進入宏任務隊列Process.nextTick()
進入微任務隊列Promise
,當即執行,輸出7,then
被添加到微任務隊列setTimeout
,進入宏任務隊列Process.nextTick()
輸出6then
,輸出8這樣第一輪循環就完全結束了,進行第二輪事件循環,也就是第一個setTimeout
console.log()
,輸出2Process.nextTick()
,進入微任務隊列Promise
當即執行輸出4,then
進入微任務隊列這樣第二輪事件循環就結束了,最後執行第二個setTimeout
,第二個setTimeout
和上面原理相似,也就不重複說明了。因此最終結果是:1,7,6,8,2,4,3,5,9,11,10,12
原文地址:傳送門