一、JavaScript是单线程的
JavaScript是一门单线程的语言,就是说它的代码是按顺序执行的,但是有时候某些任务太耗时了,在它执行完之前,后面的代码都无法执行,那这个要怎么办呢?
二、同步任务和异步任务
为了解决上述的情况,JavaScript的开发者将任务分为了两类:
在主线程中顺序执行的任务被分类为同步任务,而消耗资源多的、处理速度慢的任务,例如:图片加载,网络请求等,会被发送到任务队列(task queue)中,等待这个任务可以被执行了,任务队列才会通知主线程执行这个任务,这种任务被称为异步任务。
用流程图来表示同步任务和异步任务的执行过程:
三、事件循环(Event Loop)
当主线程执行栈中的任务被执行完之后,主线程才会去任务队列中获取异步任务,放到执行栈中执行,第一个异步任务执行完之后会继续取下一个异步任务,这样循环不断的过程就被叫做事件循环(Event Loop)。
这个循环过程可以用下图表示:
这张图可以看出异步任务最终还是在主线程的执行栈中执行,只是在这之前它们需要在任务队列中排队,等待主线程中的同步任务执行完毕开会开始执行异步任务。
四、宏任务和微任务
对于异步任务,我们还可以进行更精细的划分,将它们分为宏任务(macro-task)和微任务(micro-task)。
宏任务:
- script中的整体代码
- setTimeout、setInterval
- ajax
- DOM事件
- …
微任务:
上述的分类是基于浏览器环境,不包含node环境。
微任务的执行先于宏任务。在第一次执行的时候,先执行script中的同步代码,待执行栈空了,就去微任务的队列查看有没有微任务,如果有的话就把微任务队列清空,微任务中再添加微任务,也会被一起执行。微任务的队列清空后,就会进行页面的渲染,接着就去执行宏任务队列中的第一个任务,这个任务执行完之后再次查看微任务队列…就这样一致循环执行下去。所以大概顺序就如下所示:
全局同步代码 -> 微任务 -> 渲染页面 -> 宏任务 -> 微任务 -> 渲染页面 …
用流程图表示:
|