宏任务和微任务都是异步任务。异步任务不是按照写的顺序执行,但是也是一步步往下执行的。如果有些任务占用了整个线程,异步任务也会被阻塞。 每当一个任务存在,事件循环都会检查该任务是否正把控制权交给其他 JavaScript 代码。如果不是,事件循环就会运行微任务队列中的所有微任务。接下来微任务循环会在事件循环的每次迭代中被处理多次,包括处理完事件和其他回调之后。
区别
- 进程的切换是宏任务,线程的切换是微任务。
- 宿主环境(js运行的环境,一般为浏览器或node))发起的叫宏任务,由语言标准提供的叫微任务。
- 宏任务会触发新一轮的tick,微任务不会。
- 在每次迭代开始之后加入到任务队列中的需要在下一次迭代开始之后才会被执行。微任务可以添加新的微任务到队列中,在下一个任务开始执行且当前事件循环结束前执行完所有的微任务,这样可以提供更好的访问级别。
- 在每次新的事件循环开始迭代的时候运行时都会执行队列中的每个任务。每当一个任务退出且执行上下文为空的时候,微任务队列中的微任务会依次被执行。
JavaScript运行时
JS代码实际上是运行在执行上下文中的,每个代码段开始执行的时候都会创建一个新的上下文来运行它,并在代码退出的时候销毁掉。每个上下文在本质上都是一种作用域层级。在执行 JavaScript 代码的时候,JavaScript 运行时实际上维护了一组用于执行 JavaScript 代码的代理。每个代理都由一组执行上下文、执行上下文堆栈、一个主线程、一个用于处理workers的附加线程集、一个任务队列和一个微任务队列组成。除了一些浏览器在多个代理之间共享的主线程之外,代理的其他组成部分对该代理来说都是唯一的。
微任务解决的问题
代码和浏览器的用户界面运行在同一线程中,共享同一个事件循环。如果代码阻塞或进入无限循环,浏览器会卡死,降低用户体验。
之前微任务队列仅被内部使用来驱动promise等。queueMicrotask()使开发者可以创建一个统一的微任务队列,能在任何时候将代码安排在一个安全的时间运行(即使js执行上下文栈没有执行上下文剩余)。
queueMicrotask(function);
微任务是一个短函数,它将在当前任务完成其工作之后运行,并且在没有其他代码等待运行时,才将执行上下文的控制权返回给浏览器的事件循环。 这可以代码在不干扰任何其他(可能是更高优先级的)正在等待的代码的情况下运行,但在浏览器重新控制执行上下文之前,这可能取决于您需要完成的工作。 微任务的重要性在于它能够以特定的顺序异步执行任务。
补充
为什么定时器相关的任务是宏任务?
计时是实时的,不能被阻塞,所以定时器被设计在另一个进程中被管理,定时器任务会有进程的切换。