關於非同步方法中的巨集任務與微任務
前言
提示:我們都知道js是一個單執行緒,裡面的的請求方式分為兩種,一種是同步請求,一種是非同步請求,同步方法先執行完畢,然後再去非同步任務佇列中檢視有沒有非同步任務,有才會執行。
1.相關示例
關於非同步任務呢,又區分為兩種【巨集任務、微任務】,接下來讓我們詳細的瞭解兩種的執行順序與區別。
程式碼如下(示例):
<script>
console.log('1')
setTimeout(function () {
console.log('2')
});
new Promise(function (resolve) {
console.log('3');
resolve();
}).then(function () {
console.log('4')
setTimeout(function () {
console.log('5')
});
});
new Promise(function (resolve) {
console.log('6');
resolve();
}).then(function () {
console.log('7')
setTimeout(function () {
console.log('8')
});
});
</script>
2.程式碼解析
關於上面這段程式碼的執行順序及最後的日誌列印結果,會讓好多不熟悉【巨集任務、微任務】執行順序的小夥伴看的一臉懵逼,我第一次看到覺得最後的列印結果應該是1, 2, 3, 4, 6, 7, 5, 8,看到最後的輸出結果,才開始正視這個問題,看了許多相關案例,才瞭解一些皮毛
解析之前我們首先要知道常見的‘巨集任務’和‘微任務’有哪些,
常見的微任務有:process.nextTick、Promise和 MutationObserver(監聽DOM變化的事件)
常見的巨集任務有:setTimeout、setInterval、setImmediate、 script標籤中包含整體的程式碼塊、 I/O操作、 UI渲染等。
關於兩者之間的區別:微任務是批量執行、巨集任務則是一個一個的執行。
瞭解完這些我們就可以上面的程式碼了
這裡我們可以看到,script標籤包含的下面的程式碼塊,那麼這就屬於是第一個非同步任務,也就是巨集任務,首先去執行它
<script>
// 這裡我們都可以看到,巨集任務第一次執行,第一次的日誌輸出(1),
//這裡相信大家都能看懂,接下來我們往下面看
console.log('1')
//執行到這裡的時候,有的同學可能會問了,不是應該正常輸出(2)嗎?其實不然,我們知道,
//第一次執行完上面的巨集任務了,此時呢,會先去非同步任務佇列中查詢有沒有需要執行的微任務,所以此時先跳過它,我們接著往下走
setTimeout(function () {
console.log('2')
});
//我們通過上面瞭解到Promise是屬於微任務中的,所以這裡會執行第一個Promise物件
new Promise(function (resolve) {
//執行new Promise,正式執行第二次列印輸出(3)
console.log('3');
//這裡resolve()執行,改變了promise物件的狀態
resolve();
//那麼這裡會正常執行第三次輸出嗎?其實不是,promise執行後,改變執行狀態(成功 or 失敗)後,
//我們可以通過.then等相關方法獲取到promise物件的執行結果,所以這裡直接將一整塊的程式碼塊,
//同時丟入微任務佇列中,其中也包含setTimeout,繼續往下看
}).then(function () {
console.log('4')
setTimeout(function () {
console.log('5')
});
});
//又一個promise物件,不用說了,屬於微任務
new Promise(function (resolve) {
//執行new Promise,正式執行第三次列印輸出(6)
console.log('6');
//這裡和上面一樣resolve()執行,改變了promise物件的狀態
resolve();
//這裡不用看了,.then方法監聽promise物件的執行結果,屬於是微任務,將一整塊程式碼塊,
//包含setTimeout一起丟進微任務佇列中,那麼接下來你會問了,看程式碼書寫順序,微任務執行完了,應該執行巨集任務了吧?
//其實不對,我們想一下,第一個promise物件是不是執行完畢,.then的時候將一些程式碼塊丟進微任務佇列中了?
//是不是應該把微任務佇列中的任務也執行呢?是的...就是這樣...我們往回看,第一次.then()監聽的地方
}).then(function () {
console.log('7')
setTimeout(function () {
console.log('8')
});
});
</script>
<script>
console.log('1')
setTimeout(function () {
console.log('2')
});
new Promise(function (resolve) {
console.log('3');
resolve();
//看這裡,看這裡,第二個promise物件已經執行了,正常輸出了第三次列印(6),接下來我們上面說了,
//此時還需要檢視微任務佇列中有沒有需要執行的微任務,這時我們就發現了,第一個promise物件的.then()監聽時,
//將這一整塊程式碼都丟進微任務佇列中了,這時我們需要做的就是執行這一塊程式碼。
}).then(function () {
// 監聽第一次promise的執行結果,正式輸出第四次列印(4)
console.log('4')
//到這裡有同學會問了,這肯定該執行下面的輸出了把?彆著急,往下看
setTimeout(function () {
console.log('5')
});
});
new Promise(function (resolve) {
console.log('6');
resolve();
//看這裡,這裡的.then()也是屬於微任務佇列中的,我們還需要執行它的
}).then(function () {
// 監聽第二次promise的執行結果,正式輸出第五次列印(7),此時整個微任務佇列任務都執行完成了,
//此時我們要做的就是檢視非同步佇列中有沒有需要執行的巨集任務,按照程式碼的執行順序,我們往上翻
console.log('7')
setTimeout(function () {
console.log('8')
});
});
</script>
<script>
console.log('1')
//找到了,setTimeout屬於是巨集任務中的一種
setTimeout(function () {
//正式執行第六次列印,日誌輸出(2),接下來要做什麼呢?巨集任務執行完了,
//現在我們需要做的是去檢視非同步任務佇列中,有沒有需要執行的微任務,當前程式碼塊並沒有微任務,繼續往下找
console.log('2')
//程式碼整個的執行了,發現在setTimeout中並沒有需要執行的微任務
});
new Promise(function (resolve) {
console.log('3');
resolve();
}).then(function () {
console.log('4')
// 沒有需要執行的微任務,此時我們再去執行這個巨集任務
setTimeout(function () {
// 正式輸出第七次列印,日誌輸出(5)
console.log('5')
// 巨集任務執行完成了,我們需要做的還是去檢視微任務佇列中有沒有需要執行的微任務,如果有,
//批量執行,當前程式碼塊並沒有
});
});
new Promise(function (resolve) {
console.log('6');
resolve();
}).then(function () {
console.log('7')
//執行到這裡了,還是沒有微任務,那就執行這個巨集任務
setTimeout(function () {
//正式輸出第八次列印,輸出日誌(8)
console.log('8')
//執行完巨集任務了,再次檢視有沒有需要執行的微任務,發現此時還是沒有微任務,
//那就找一下有沒有巨集任務吧,此時整個非同步佇列中,巨集任務、微任務全部執行完成了
});
});
</script>
此時我們開啟瀏覽器,看一下控制檯,最後的列印結果為: 1、3、6、4、7、2、5、8
總結
以上就是今天要講的內容,本文僅僅簡單介紹了非同步方法中‘巨集任務’和‘微任務’的區別,大家第一次瞭解可能不是那麼好理解,多用幾次就好了,誰還不是踩著坑過來的;
關於js中事件執行的流程:
第一步:先執行所有的同步佇列中的同步任務
第二步:執行完畢再去執行第一個巨集任務
第三步:執行完畢第一個巨集任務,再去‘微任務’佇列中檢視,有沒有需要執行的‘微任務’,如果有,批量執行,沒有就執行下一個‘巨集任務’
第四步: 執行完第一批‘微任務’,此時去執行第二個巨集任務
第五步:執行完巨集任務,再去‘微任務’佇列中檢視有沒有‘微任務’,如果有,批量執行,沒有在執行下一個巨集任務
大致就是這樣一個流程,大家記住一句話就行‘有微則微,無微則巨集’
相關文章
- JavaScript的巨集任務與微任務JavaScript
- 任務佇列,巨集任務與微任務佇列
- js中的巨集任務和微任務JS
- JS中EventLoop、巨集任務與微任務的個人理解JSOOP
- 巨集任務和微任務
- 微任務、巨集任務與Event-LoopOOP
- JavaScript巨集任務和微任務JavaScript
- js的setTimeout和Promise—同步非同步和微任務巨集任務JSPromise非同步
- Event Loop、 巨集任務和微任務OOP
- 前端急速解決非同步之微任務和巨集任務前端非同步
- macrotask 巨集任務 + microtask 微任務區別Mac
- 總結:JavaScript非同步、事件迴圈與訊息佇列、微任務與巨集任務JavaScript非同步事件佇列
- 瞭解js執行機制——微任務與巨集任務JS
- async與await以及巨集微任務AI
- JavaScript的事件迴圈與巨集微任務JavaScript事件
- 微任務和巨集任務哪個先執行
- javascript事件環微任務和巨集任務佇列原理JavaScript事件佇列
- JS事件迴圈機制(event loop)之巨集任務/微任務JS事件OOP
- UI 阻塞行為:微任務與宏任務UI
- 同步任務與非同步任務執行順序非同步
- node基礎面試事件環?微任務、巨集任務?一篇帶你飛面試事件
- SpringBoot與非同步任務、定時任務、郵件任務Spring Boot非同步
- 如何理解 JS 非同步程式設計的,EventLoop、訊息佇列,什麼是巨集任務,什麼是微任務?JS非同步程式設計OOP佇列
- 關於非同步任務設計的幾點思考非同步
- 等待多個非同步任務的方法非同步
- 使用ant巨集定義任務
- JS/NodeJS中的非同步任務與事件環NodeJS非同步事件
- 關於beego的定時任務Go
- servlet非同步任務Servlet非同步
- javaScript 之 蟻人<微任務>JavaScript
- 專案任務與運維任務的衝突運維
- Celery非同步任務框架非同步框架
- AsyncTask非同步任務類非同步
- Android非同步任務Android非同步
- 終止非同步任務非同步
- 基於Django與Celery實現非同步佇列任務Django非同步佇列
- Django配置celery執行非同步任務和定時任務Django非同步
- Django 如何使用 Celery 完成非同步任務或定時任務Django非同步