概念
任务轮询也就是事件循环(event loop),就是js引擎执行事件的顺序。
事件循环基于两个原则:一次处理一个任务;一个任务开始后直到运行完成,不会被其他任务中断。
事件循环首先检查宏任务队列
- 如果有任务等待,就执行排在第一个宏任务,执行完毕之后不会继续执行下一个宏任务而是去查看微任务队列,微任务队列如果有任务则依次全部完成,微任务队列为空之后看是否需要重新渲染,完之后又重新查看宏任务队列,执行第二个宏任务,如此循环往复。
- 如果没有任务等待(宏任务队列为空),直接查看微任务队列,有就全部执行,然后和1步骤一样。
注意:
- js开始执行时主任务队列当作一个宏任务。
- 单次循环最多处理一个宏任务。
- 任务处理的顺序都是先进先执行。
- 只有任务执行完毕后页面才会进行渲染
宏任务和微任务
任务轮询就是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()