事件循环
事件循环
异步操作会将相关回调添加到任务队列中,但是不是一声名就会进入任务队列,而是在不同的时机进入任务队列。而且,不同类型的异步操作添加到任务队列的时机也不同,比如 onclick, setTimeout,ajax 处理,他们添加到任务队列的时机都不同,这些异步操作是由浏览器内核的 webcore 来执行的,webcore 包含下图中的 3 种 webAPI,分别是 DOM Binding、network、timer 模块。
DOM Binding 模块处理一些 DOM 绑定事件,如 onclick 事件触发时,回调函数会立即被 webcore 添加到任务队列中。
network 模块处理 Ajax 请求,在网络请求返回时,才会将对应的回调函数添加到任务队列中。
timer 模块会对 setTimeout 等计时器进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。
JS 只有一个线程,称之为主线程。而事件循环,是在主线程中的执行栈中的代码,执行完毕之后,才开始执行的。所以,主线程中要执行的代码时间过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来观察要执行的事件回调,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中由主线程执行。
事件循环,事件循环也有很多种,比如 window event loop、worker event loop,还有 worklet event loop
一个事件循环,有一个或者多个任务队列,一个任务队列是任务的集合,注意,微观任务队列(microTask queue)不是任务队列,任务队列实际上就是指宏观任务 macroTask 队列。
每一个任务都有一个任务源,任务源有以下几种:https://html.spec.whatwg.org/multipage/webappapis.html#generic-task-sources
- DOM manipulation task source:DOM 操作任务源
- user interaction task source:用户交互任务源
- networking task source:网络任务任务源
- navigation and traversal task source:导航和遍历任务源,这个不懂
每个任务被定义为来自特定的任务源。对于每个事件循环,每个任务源必须与特定的任务队列相关联。
本质上,任务源在标准规范中用于分离逻辑上不同类型的任务,user agent 可能希望对这些任务进行区分。user agent 使用任务队列来合并给定事件循环中的任务源。也就是说一个任务源一个队列
例如,user agent 可以有一个任务队列用于鼠标和键盘事件 (用户交互任务源与之关联),另一个任务队列用于所有其他任务源的关联。然后,使用在事件循环处理模型的初始步骤中授予的自由度,它可以在四分之三的时间内优先处理键盘和鼠标事件,而不是其他任务,从而保持界面的及时响应,但不会占用其他任务队列。注意,在此设置中,处理模型仍然强制 user agent 永远不会无序地处理来自任何一个任务源的事件。也就是说事件都是有序处理的,事件的顺序就是其在队列里的顺序
每一个事件循环总有一个当前正在执行的任务,一开始的时候为 null
每一个事件循环都有一个 microtask queue,microtask 只是队列微任务算法创建的任务的通俗说法而已。
,只会处理一个 macroTask,和这个 macroTask 产生的所有的 microTask,
macrotask(按优先级顺序排列): script(你的全部 JS 代码,“同步代码”), setTimeout, setInterval, setImmediate, I/O,UI rendering
microtask(按优先级顺序排列):process.nextTick,Promises(这里指浏览器原生实现的 Promise), Object.observe, MutationObserver
js 引擎首先从 macrotask queue 中取出第一个任务,执行完毕后,将 microtask queue 中的所有任务取出,按顺序全部执行;
然后再从 macrotask queue(宏任务队列)中取下一个,执行完毕后,再次将 microtask queue(微任务队列)中的全部取出;
循环往复,直到两个 queue 中的任务都取完。
其实我有一个问题,TODO
①多个宏任务队列,本轮宏任务及微任务队列里所有微任务都执行完之后,下一轮宏任务该取哪个宏任务队列中的任务呢?
这里其实说明了,我们其实不需要关注异步任务有多少个队列,每一次取那个队列的哪个任务,我们只需要直到,不管有多少个队列,队列里的任务是什么,他们都是按照这个优先级来执行的,
http://www.yangzicong.com/article/3
上面这篇文章的作者也说了,一个事件循环可以有多个任务队列,队列之间可有不同的优先级,同一队列中的任务按先进先出的顺序执行,但是不保证多个任务队列中的任务优先级,具体实现可能会交叉执行。
这个就不深究了
https://segmentfault.com/a/1190000011198232
讲得异常清楚,异常简单有效
其实具体的机制,我还是不是很清楚,但是对于解决日常开发中的问题,已经足够了,因此决定不再花费更多的时间在这个上面了,