概念
任務輪詢也就是事件循環(event loop),就是js引擎執行事件的順序。
事件循環基于兩個原則:一次處理一個任務;一個任務開始后直到運行完成,不會被其他任務中斷。
事件循環首先檢查宏任務隊列
- 如果有任務等待,就執行排在第一個宏任務,執行完畢之后不會繼續執行下一個宏任務而是去查看微任務隊列,微任務隊列如果有任務則依次全部完成,微任務隊列為空之后看是否需要重新渲染,完之后又重新查看宏任務隊列,執行第二個宏任務,如此循環往復。
- 如果沒有任務等待(宏任務隊列為空),直接查看微任務隊列,有就全部執行,然后和1步驟一樣。
image
注意:
- js開始執行時主任務隊列當作一個宏任務。
- 單次循環最多處理一個宏任務。
- 任務處理的順序都是先進先執行。
- 只有任務執行完畢后頁面才會進行渲染
宏任務和微任務
image
任務輪詢就是setTimeout不是準時執行的原因。
題
async function async1() {
console.log('async1 start');
await async2();
console.log('asnyc1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
console.log('promise1');
reslove();
}).then(function () {
console.log('promise2');
})
console.log('script end');
/**首先整個代碼當作一個宏任務開始執行**/
//script start
/**遇到setTimeout 指定時間到之后回調函數放入宏任務隊列**/
//async1 start
/**遇到await async2(); 執行async2();await后面的代碼console.log('asnyc1 end')當作then異步調用放入微任務隊列;**/
//async2
/**遇到Promise同步執行,then放入微任務隊列**/
//promise1
//scriptend
/**主線任務執行完畢,開始執行微任務隊列,此時微任務隊列有兩個任務**/
//async1 end
//promise2
/**第一輪任務輪詢完畢,第二輪開始,查看宏任務隊列**/
//setTimeOut
應用
拆分任務,防止堵塞
let i = 0
let start = Date.now()
// function count(){
// for(let j=0;j<1e9;j++){
// i++
// }
// }
// count()
// console.log(233)
// alert(`log in ${Date.now() - start}ms`)
function count() {
do {
i++
} while (i % 1e6 != 0)
console.log(1)
if (i == 1e9) {
alert(`done in ${Date.now() - start}ms`)
} else {
setTimeout(count)
}
}
count()
console.log(233)
alert(`log in ${Date.now() - start}ms`)
進度條
//#progress{
// background-color: aquamarine;
// }//css
//<div id="progress"></div> //html
function getProgress(){
let i=0;
(function run(){
// i++
progress.innerHTML=i
progress.style.width=i+'%'
if(++i<=100){
setTimeout(run,20)
console.log(i)
// run()//太快了
}
})()
}
getProgress()