聊聊前端面試之輸出順序

春節後,新一輪跳槽風暴不知道可否吹暖今冬的裁人寒冬。然而,職場現狀就是愈來愈多的小公司也在效仿各大互聯網牛場面試要求,對於底層知識要求愈來愈深,管他用着用不着的,先面了再說。本篇跟你們聊聊面試常見題型之顯示順序問題。web

注:本篇分析爲在瀏覽器環境中排序顯示。
面試

Nodejs編程是全異步,事件引擎爲libuv。
編程

1、JavaScript運行機制

關於運行機制聊四個關鍵點:瀏覽器

  • 單線程:同一時間只能解決一件事,是JS核心特徵。JS爲何不能多線程?由於JS是瀏覽器腳本語言,主要用於用戶交互與DOM操做;
  • 任務類型:同步任務異步任務。同步任務是主線程上的排隊等待解決的任務,只有完成一項任務,才能夠進行下一個任務;異常任務,不進入主線程任務,而是進入「任務隊列」,只有主線程的任務完成後,纔會召喚「任務隊列」上任務並執行;
  • 任務隊列:是一個事件隊列,I/O設備完成一項任務,就會在「任務隊列」裏添加一個事件。注意,必須I/O設備完成有結果,纔會進入到「任務隊列」;
  • 事件循環(Event Loop):主線程不斷的循環從「任務隊列」讀取事件的運行機制。

2、任務的階級鬥爭

JavaScript任務運行機制圖
bash

第一階級:同步任務

一、皇帝豪飲兩碗鹿血,問有個叫EventLoop的公公,今晚誰來陪睡,EventLoop掐指一算,正宮幾個「同步任務「娘娘都送過禮,我就按照送禮順序來給她們安排吧。多線程

同步任務優先執行,先進先出。
異步

第二階級:異步任務(微任務)

二、幾晚事後,全部送過禮的「同步任務」娘娘輪流服侍皇帝一遍。如此同時,秀宮的宮女們忙着化妝整容。原來,宮裏有個不成文的規定,只有收拾好本身的宮女才能夠排隊等待皇帝的召喚,到時候公公EventLoop會按照排隊次序向皇帝安排服侍。async

三、何時才輪到宮女們服侍呢?是「同步任務」娘娘們服侍一遍後,畢竟公公EventLoop爲了保護本身的飯碗,得讓皇帝不斷嚐鮮。函數

同步任務執行的同時,異步任務在事件棧完成後,異步任務進入「任務隊列」;
oop

事件循環(Event Loop)驅使主線程在所有同步任務完成後,從「任務隊列」讀取事件,如此不斷循環;

任務隊列執行先進先出;

第三階級:異步任務--定時器(宏任務)

四、在秀宮有兩個宮女姓SetTimeout和setInterval,人老珠黃,雖然化妝技術還能夠,也送過了禮,無奈確實不上檔次,負責秀宮的公公就讓她倆排在了全部宮女的後邊,等着唄。

五、這倆宮女終於看到但願了,可誰知又來一批年輕漂亮的秀女,怎麼辦,等着唄。

六、終於,前先後後好幾批年輕秀麗的宮女們服侍完皇帝,輪到這兩位了,按照老規則,誰先來的誰優先,倆人對視苦笑,回頭一看,又來幾個姓SetTimeout和setInterval的宮女...

同時嵌套在異步操做的任務,會將嵌套在異步的下一次任務隊列中;

定時器任務添加到任務隊列的尾部;

3、案例分析

基於今日頭條的面試題改造

async function async1() {
    console.log(1)
    await async2()
    console.log(2)
    return await 3
}
async function async2() {
    console.log(4)
}

setTimeout(function() {
    console.log(5)
}, 0)

async1().then(v => console.log(v))
new Promise(function(resolve) {
    console.log(6)
    resolve();
    console.log(7)
}).then(function() {
    console.log(8)
})
console.log(9)複製代碼
  • 從代碼第一行開始,異步函數async一、async2構建完未執行。
  • 按照代碼順序,首先該執行的應該是setTimeout,怎奈又不是正宮,長得又不秀麗,只能在任務隊列最後等着。
  • 運行到async1.then()時,async1返回一個Promise對象(異步函數實際上是封裝的Promise.resolve()Promise對象是一個構造函數),因此在執行async1時,首先將非resolve、reject函數加入主線程,上題中首先執行console.log(1)await async2
    輸出1,4。感受await挺孫子的,執行完本身的函數就跳出來async函數。
  • 繼續看,異步函數async1的then執行這個時候進入事件棧,由於還在等待異步函數async1返回值,等着吧。
  • 繼續向下執行遇到真正的Promise對象了,二話不說,執行下先,console.log(6)console.log(7)直接加入到主線程,輸出6,7。同時將異步函數console.log(8)放在儲秀宮,雖然屬於第二階級,起碼仍是第二階級的老大麼。
  • 單純的console.log(9)說,咱也是第一階級的,雖然最後一位,侍架一晚,輸出了
    9
  • 同步人物結束了,Event Loop開始召喚任務隊列,console.log(8)說我是秀女中的第一位,好,就你了。因而,生出了8
  • setTimeout翹首以盼,誰知,執行完本輪又跳到到異步函數async1,率先看到了console.log(2),因此輸出了2
  • 緊接着,又遇到了await了,還好,結束了,返回的值扔給了async的異步函數,獲得了值,抓緊時間執行,獲得結果了,終於能夠進入任務隊列,這時主線程也是空的,執行下結果吧,輸出了3
  • 全部微任務結束了,該宏任務大展拳腳了,setTimeout輸出了值,5
以上試題分析完畢,輸出結果順序爲: 1,4,6,7,9,8,2,3,5

4、最後

以上是我的對於任務執行順序的理解,如理解有誤,但願大神多多指教。

相關文章
相關標籤/搜索