event - 事件 loop - 循环,既然叫事件循环,那么循环的点在哪? 循环的是一个又一个的任务队列,这些任务队列由宏任务和微任务构成
一次事件处理中,最多处理一个宏任务,可是会处理全部的微任务,任务开始后,会将内部全部的宏观函数加到宏观队列等待,会将全部的围观函数加到微观队列等待,当前宏任务处理完毕后,开始逐个处理微任务,当微任务执行处理完成,会检查是否须要更新ui,若是是则从新渲染ui。以后再次检查宏观任务队列中的下一个宏观任务,取出来而且执行promise
浏览器的渲染,不一样浏览器处理是不一样的,可是大部分浏览器选择通常是一秒钟60帧率(也就是60fps),这意味着浏览器会在16ms左右渲染一帧,因此咱们单个任务和该任务的全部附属微任务都应该在16ms内完成,以达到显示平滑流畅。浏览器
console.time("settimeout"); setTimeout(() => { console.log('settimeout执行') console.timeEnd("settimeout"); }, 1000); for (let a = 0; a < 50000; a++) { console.log(a) }
time会输出多少呢?这种事件是怎么触发的?app
代码是在一秒钟后才加入事件队列,以后等待执行。怎么证实,很简单咱们在拿出一个定时器异步
console.time("settimeout"); console.time("settimeout2"); setTimeout(() => { console.log('settimeout执行') console.timeEnd("settimeout"); }, 1000); setTimeout(() => { console.log('settimeout2执行') console.timeEnd("settimeout2"); }, 1); for (let a = 0; a < 50000; a++) { console.log(a) }
明明后声明的定时器2,却先执行了,不知道有没有发现,定时器1和定时器2执行时间,很接近!!!这很重要,为何会这样,这就是今天所说的事件队列,当1毫秒时候,定时器2被加入了事件队列,当一秒钟时候定时器1被加入事件队列,而后for执行完后,队列中下一个任务为定时器2,可是他只有一个console故而很快,因此拿出了定时器进行执行。再来看个额外例子,来巩固下:async
console.time("settimeout"); console.time("settimeout2"); setTimeout(() => { console.log('settimeout执行') console.timeEnd("settimeout"); }, 1000); for (let a = 0; a < 50000; a++) { console.log(a) } setTimeout(() => { console.log('settimeout2执行') console.timeEnd("settimeout2"); }, 1);
枯燥无味的定义基本就这样,咱们来从实践来作分析函数
从练习题来讲oop
console.log(1) setTimeout(function () { console.log(2) setTimeout(function () { console.log(3) }) }) setTimeout(function () { console.log(4) }) console.log(5)
第一次运行以后
学习
这时当前主进程队列已经结束,开始检测微任务队列是否还有未完成的任务,发现微任务队列已经空了因此,当前宏任务队列结束,开始下一组宏任务优化
settimeout2任务完结,检查当前微任务队列为空,开始下一组宏任务ui
因此最终答案为:
1,5,2,4,3
console.log(1) setTimeout(function () { console.log(2) setTimeout(function () { console.log(3) }) }) setTimeout(function () { console.log(4) }) console.log(5)
这样就会输出1,5,2,3,4
tips: setTimeout写的1000不等于他就是在上一次事件结束后的1000ms,而是以他声明开始就进行计时的。不过这不是本篇文章的核心,咱们不深究他的逻辑,继续看第二个例子
console.log(1) setTimeout(() => { console.log('2') Promise.resolve(4).then((res) => console.log(res)) }, 0); setTimeout(() => { console.log('3') }, 0);
主进程执行完毕,检查微任务队列为空,当前宏任务结束,开启下一组宏任务
settimeout宏任务执行完毕,检查宏任务队列,拿出settimeout3的宏任务,将它拿出来执行。这个比较简单我们就不画图了
因此本题答案为1,2,4,3
let promise = new Promise(function(resolve, reject) { console.log('1'); resolve(); }); promise.then(function() { console.log('2'); }); console.log(3)
检查宏任务队列发现为空,因此本次代码结束
答案为:1,3,2
console.log(1); setTimeout(function(){ console.log(2); }, 0); Promise.resolve().then(function(){ console.log(3); }).then(function(){ console.log(4); });
当前宏任务已经结束,查看宏任务队列中发现还有settimeout没有执行,将它取出来执行,
输出2.
因此本题答案为:1,3,4,2
setTimeout(()=>{ console.log('1'); },0); var obj={ func:function () { setTimeout(function () { console.log('2') },0); return new Promise(function (resolve) { console.log('3'); resolve(); }) } }; obj.func().then(function () { console.log('4') }); console.log('5');
主线进程及其微观进程执行完毕,会拿出下一组settimeout1执行,执行后会进行检测微观队列,若是没有则会继续往下取出settimeout2执行。至此程序结束。
因此本题答案为:3,5,4,1,2
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) resolve() }).then(() => { console.log(3) throw(new Error('错误')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('错误2')) })
至此,当前宏任务结束。检查宏任务队列。取出下一组宏任务,settimeout6,并执行
因此答案为:1,2,5,7,3,4,8,Error,6
最后留两道题给你们作学习用。
若是不能一眼看出。能够像我同样画一个图。进行梳理。本文中为了代码整齐,settimeout都是直接简化为尽快执行。其实settimeout应该是在到达他声明的时间时候,才进入宏观队列排队的。
根据如下规则,你将不会在遇到事件队列的问题
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) setTimeout(() => { console.log(9) }, 0); resolve() }).then(() => { console.log(3) throw(new Error('错误')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('错误2')) })
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) setTimeout(() => { console.log(9) }, 0); resolve() }).then(() => { console.log(3) throw(new Error('错误')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('错误2')) }) requestAnimationFrame(function() { console.log(10) })
怎么利用这些,在代码中优化本身的代码,举个例子来讲
for (let i = 0 ; i<50000;i++) { const div = document.createElement('div') div.innerText = i document.body.appendChild(div) }
function slice(startSplitNumber, total, sliceNumber, cb) { const oneNumber = total/sliceNumber const start = startSplitNumber * oneNumber const end = (startSplitNumber + 1) * oneNumber if (start >= total) return setTimeout(() => { for(let i = start; i < end;i++) { cb(i) } slice(startSplitNumber + 1, total, sliceNumber, cb) }, 0) } slice(0, 50000, 5000, function (current) { const div = document.createElement('div') div.innerText = current document.body.appendChild(div) })