单线程就意味着,一次只能执行一个任务,其他任务都需要排队等待
同步任务:是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务:不进入主线程、通过事件循环机制处理,在任务队列中注册回调函数最终拿到结果
事件循环
- 所有同步任务在主线程上执行,形成一个执行栈,也就是上图蓝色箭头表示
- 主线程以外有一个异步任务队列(红色箭头),会等到异步任务返回结果后将它放入任务队列
- 当主线程中执行栈代码执行完毕,也就是同步任务执行完毕,就会开始读取任务队列代码,再放入执行栈中执行
只要主线程执行栈空了,就会去读取任务队列,这个过程是循环不断的,这种运行机制就叫做事件循环
console.log(1);
setTimeout(()=>{console.log(2);},0)
setTimeout(()=>{console.log(3);},1000)
setTimeout(()=>{console.log(4);},0)
console.log(5);
输出了 1 – 5 – 2 – 4 – 3
定时器都是异步任务,会先被放入异步任务队列当中,需要等待异步任务返回结果后,再将回调函数放入任务队列当中,等待主线程来执行,因此,4 会在 3 之前输出
宏任务和微任务
宏任务队列可以有多个,微任务队列只有一个
- 宏任务有:HTML解析、鼠标事件、键盘事件、网络请求、执行主线程js代码和定时器
- 微任务有:
promise.then
,DOM 渲染,async
,process.nextTick
-
当执行栈中的同步任务执行完毕后,先执行微任务
-
微任务队列执行完毕后,会读取宏任务
-
执行宏任务的过程中,遇到微任务,再加入微任务队列
-
宏任务执行完后,再次读取微任务队列,依次循环
简单的话来总结:微任务永远在宏任务执行之前被执行完毕
由于代码的入口就是一个 script
标签。因此,全局任务属于宏任务