在 javascript 面試中對非同步的理解

追_光_者發表於2019-03-11

非同步概念

對於 js 不知道非同步是什麼,為什麼需要有非同步的同學來說,可以先看看我的這篇文章 如錯誤之處,請求指點,謝謝閱讀。


非同步進一步理解

對於已經瞭解了非同步的基本概念的同學,我們可以來看一下,下面的這個例子,有助於我們更好的理解非同步(注意chrom: 版本:72.0.3626.121 版本不同結果有點差異)
複製程式碼
// 今日頭條面試題
async function async1() {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
}
async function async2() {
   console.log('async2')
}
console.log('script start')
setTimeout(function () {
   console.log('settimeout')
})
async1()
new Promise(function (resolve) {
   console.log('promise1')
   resolve()
}).then(function () {
   console.log('promise2')
})
console.log('script end')

// result:
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// settimeout
複製程式碼

執行過程的分析:

  1. 遇到 console.log('script start'), 放在主執行緒中立即執行,所以第一步先輸出 script start
  2. 遇到 setTimeout,因為 setTimeout 是非同步的,所以將回撥函式放入非同步佇列中去等待,等待主執行緒中的任務執行完之後,再通過事件輪詢的方式去呼叫
  3. 遇到 async1 函式的呼叫,此時走到 async1 函式裡面輸出 async1 start
  4. 遇到 await 關鍵字,進入到 async2 函式中輸出 async2,將 await 後面的程式碼放入微任務中,執行後面的操作
  5. 遇到 Promise 直接輸出promise1,將回撥函式放入微任務中,執行後面的操作
  6. 遇到 console.log('script end'), 放在主執行緒中立即執行,所以第一步先輸出 script end,到這個時候主執行緒中的程式碼就執行完了
  7. 主執行緒中的程式碼執行完之後,立即執行所有的微任務。分別輸出 async1 end,promise2
  8. 最後通過事件輪詢的方式將非同步佇列中程式碼,拿到主執行緒中來執行 (輸出 settimeout)
  9. 重複步驟8

注意

  • await 關鍵字必須在用 async 關鍵字修飾的函式中才能使用。
  • async 語法其實也就是 Promise 語法。

上面例子中的這部分程式碼可以轉化為:

轉化前:

    async function async1() {
       console.log('async1 start')
       await async2()
       console.log('async1 end')
    }
複製程式碼

轉化後:

    async function async1() {
       console.log('async1 start')
       new Promise((resolve, reject) => {
           this.async2()
           resolve()
       })
       .then(body => {
           console.log('async1 end')
       })
    }
複製程式碼

為了鞏固大家可以練下下面兩個題目:

async function async1() {
    console.log('async1 start');
    await async2();
    setTimeout(function() {
        console.log('setTimeout1')
    },0)
}
async function async2() {
	setTimeout(function() {
		console.log('setTimeout2')
	},0)
}
console.log('script start');

setTimeout(function() {
    console.log('setTimeout3');
}, 0)
async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');
複製程式碼
async function async1() {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
}
async function async2() {
   console.log('async2')
	new Promise((resolve, reject) => {
		console.log('promise3')
		resolve()
	})
	.then(body => {
		console.log('promise4')
	})
}
console.log('script start')
setTimeout(function () {
   console.log('settimeout')
})
async1()
new Promise(function (resolve) {
   console.log('promise1')
   resolve()
}).then(function () {
   console.log('promise2')
})
console.log('script end')
複製程式碼

答案:

    script start
    async1 start
    promise1
    script end
    promise2
    setTimeout3
    setTimeout2
    setTimeout1
複製程式碼
    script start
    async1 start
    async2
    promise3
    promise1
    script end
    promise4
    async1 end
    promise2
    settimeout
複製程式碼

謝謝大家的閱讀,不對之處,請指教。

相關文章