事件轮询概念
事件轮询(Event Loop)是一个很重要的概念,指的是计算机系统的一种运行机制。JavaScript语言就是采用的这种机制,来解决单线程运行带来的一些问题。
想要理解EventLoop,就要从程序的运行模式讲起。运行以后的程序叫做"进程"(process),一般情况下,一个进程一次只能执行一个任务。
如果有很多任务需要执行,不外乎三种解决方法。
(1)排队。因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。
(2)新建进程。使用fork命令,为每个任务新建一个进程。
(3)新建线程。因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。
以JavaScript语言为例,它是一种单线程语言,所有任务都在一个线程下完成,即采用上面的第一种方法,一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现假死的状态,因为JavaScript停不下来,也就无法响应用户的行为。
很多人问为什么JavaScript不能实现多线程呢,例如如果是多线程的话,多个线程去操作同一个Dom元素,那么结果就造成一个很严重的问题,所以js是单线程的,但如果完全由上至下的执行代码,前面的代码没有执行完,后面必须要等待当前执行完毕,这样的效率是非常低的,所以有了异步的概念,JavaScript 的主线程是单线程的,但是也有其他的线程去帮我们实现异步操作,比如Ajax 线程、定时器线程、事件线程。
JavaScript的任务
1.宏任务
宏任务包括整体代码script,setTimeout,setInterval, I/O,UI Rendering
2.微任务
微任务包括Promise.then(非new Promise),process.nextTick
不同类型的任务会进入不同的Event Queue,有宏任务的队列和微任务的队列。
我们来看下面这道题就可以清晰了解宏、微任务区别:
setTimeout(() => { console.log( 'd' ); }, 0);
new Promise(resolve=>{
console.log('a');
for(let i =0;i<10000;i++){ i == 9999 && resolve(); } console.log( 'b' ) }).then(()=>{ console.log( 'e' ) })
console.log( 'c' )
答案是 a b c e d,让我们来看看执行流程:
通过图片我们可以看出,进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务
所以上面那道题是宏任务会先将延时器放到事件队列中,等待下一轮执行宏任务才会执行延时器,继续找宏任务a b c ,直到没有宏任务就会执行微任务,也就是e ,微任务也执行完毕,就会开启新一轮的执行宏任务,所以最后打印d