JavaScript非同步程式設計(五)之async和巨集任務微任務
技術標籤:javascript前端
Promise 雖然主要是用來處理非同步任務的,但我們深入理解 Promise 並不是純為了來處理非同步任務,因為在 ES7 裡的 async 和 wait 能更簡單的處理非同步任務:
// 一個非同步任務,在time毫秒後返回一個狀態為reject的Promise物件
function ajax(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`完成了-${time}`)
} , time)
})
}
// 主函式
async function main() {
const ajax1 = await ajax(600)
console.log(ajax1)
const ajax2 = await ajax(500)
console.log(ajax2)
const ajax3 = await ajax(700)
console.log(ajax3)
}
main()
如上程式碼,在主函式前新增關鍵字 async ,主函式裡面的每個非同步任務前加上關鍵字 await ,並分別用一個變數接收返回值,非同步任務處理便完成了。
上邊程式碼按順序執行:
可見,上面的3個非同步任務雖然耗時各不相同,但都按照執行的先後順序完成,並不會受耗時長短的影響。
稍加完善,正式專案中程式碼可能如下:
async function main() {
try {
const users = await ajax('/api/users.json')
console.log(users)
const posts = await ajax('/api/posts.json')
console.log(posts)
const urls = await ajax('/api/urls.json')
console.log (urls)
} catch (e) {
console.log(e)
}
}
async 和 wait 就是這麼樸實無華,需要注意的是 await 不能單獨使用,必須在 async 修飾的主函式裡使用,不過 await 單獨使用的提案已經提出,也許不久的將來 await 就可以單獨使用了,那時將更加的方便。
巨集任務和微任務
先看一段程式碼:
console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise((resolve, reject) => {
console.log('promise')
resolve('then')
}).then(res => {
console.log(res)
})
console.log('end')
上面程式碼的執行順序,估計很多人都理不對,正常的執行順序如下:
這裡涉及巨集任務和微任務的概念。
new Promise() 本身和同步任務執行模式沒區別,會直接執行,不會去訊息佇列裡排隊,所以在第一輪執行中,所有同步任務會按續執行,即按續列印:“start”、“promise”、“end”。
執行到 setTimeout() 的時候,會產生一個巨集任務,這個巨集任務會進入到訊息佇列中排隊,等待同步任務執行完之後才會執行。
在 new Promise() 執行的時候,它後面的 then 產生一個微任務,這個微任務也會進入訊息佇列中排隊,等待同步任務執行完之後才會執行。
同步任務執行完之後,此時訊息佇列中有一個巨集任務和一個微任務,微任務的執行優先度比巨集任務高,所以先執行微任務,再執行巨集任務,所以隨後先後列印:“then”、“setTimeout”。
如果你覺得理解了巨集任務微任務,那麼再看看下面這個程式碼:
new Promise((resolve, reject) => {
console.log(1)
resolve()
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
})
new Promise((resolve, reject) => {
console.log(111)
resolve()
}).then(() => {
console.log(222)
}).then(() => {
console.log(333)
})
執行試試吧,看看是否與預想的一樣?
文章內容輸出來源:拉勾大前端高薪訓練營,以上文章中的內容根據老師講課的語音和程式碼,結合自己的理解編輯完成。