事件循环机制-任务队列、webAPI、JS主线程的相互协同
2017-12-13 13:39
661 查看
一、JS单线程、异步、同步的概念
众所周知,JS是单线程,虽然有webworker酱紫的多线程出现,但也是在主线程的控制下。webworker仅仅能进行计算任务,不能操作DOM,所以本质上还是单线程。 单线程即任务是串行的,后一个任务需要等待前一个任务的执行,这就可能出现长时间的等待。但由于类似ajax网络请求、setTimeout时间延迟、DOM事件的用户交互等,这些人物并不消耗CPU,是一种空等,资源浪费,因此出现了异步。通过将任务交给相应的异步处理模块去处理,主线程的效率大大提升,可以并行的去处理其他操作。当异步处理完成,主线程空闲时,主线程读取相应的callback,进行后续的操作,最大程度的利用CPU。此时出现了同步和异步执行的概念,同步执行是主线程按照顺序,串行执行任务;异步执行就是CPU跳过等待,先处理后续的任务(CPU与网络模块、timer等并行进行任务)。由此产生了任务队列与事件循环,来协调主线程与异步模块之间的工作。
二、事件循环机制
如上图为时间循环示例图(或JS运行机制图),流程如下:
1. step1:主线程读取JS代码,此时为同步环境,形成相应的堆和执行栈; 2. step2:主线程遇到异步任务,指给对应的异步进程进行处理(webAPI); 3. step3:异步进程处理完毕(Ajax返回,DOM事件处理,Timer到时等),将相应的异步任务推入任务队列; 4. step4:主线程执行完毕,查询任务队列,如果存在任务,则取出一个任务推入主线程处理(先进先出); 5. step5:重复执行step2、3、4;称为事件循环。 执行的大意: 同步环境执行(step1) -> 事件循环1(step4) -> 事件循环2(step4)...
其中的异步进程有:
1. 类似onclick等,由浏览器内核的DOM binding模块处理,事件触发时,回调函数添加到任务队列中; 2. setTimeout等,由浏览器内核的Timer模块处理,时间到达时,回调函数添加到任务队列; 3. Ajax,有浏览器内核的Network模块处理,网络请求返回后,添加到任务队列中。
三、任务队列
如上示意图,任务队列存在多个,同一任务队列内,按队列顺序被主线程取走;不同任务队列之间,存在着优先级,优先级高的优先获取(如用户I/O);3.1、任务队列的类型
任务队列存
4000
在两种类型,一种为microtask queue,另一种为,macrotask queue。
图中所列出的任务队列均为macrotask queue,而ES6的promise[ECMAScript标准]产生的任务队列为microtask queue。
3.2、 两者的区别
microtask queue:唯一,整个事件循环当中仅存在一个;执行为同步,同一个事件循环中的microtask会按队列顺序,串行执行完毕。
macrotask queue:不唯一,存在一定的优先级(用户I/O部分优先级更高);异步执行,同一事件循环中只执行一个。
3.3、 更完整的事件循环流程
将microtask加入到JS运行机制流程中,则:
step1、2、3同上
step4:主线程查询任务队列,执行microtask queue,按序执行执行,全部执行完毕;
step5:主线程查询任务队列,执行macrotask queue,取队首任务执行,执行完毕;
step6:重复step4、step5。
microtask queue中的所有callback处在同一个事件循环中,而macrotask queue中的callback有自己的事件循环。
简而言之:同步环境执行 -> 事件循环1(microtask queue的All) -> 事件循环2(macrotask queue中的一个) -> 事件循环1(microtask queue的All) -> 事件循环2(macrotask queue中的一个)…
利用microtask queue可以形成一个同步执行的环境,但如果microtask queue太长,将导致macrotask任务长时间执行不了,最终导致用户I/O无响应等,所以使用需慎重。
四、示例、验证
console.log('1, time = ' + new Date().toString()) setTimeout(macroCallback, 0); new Promise(function(resolve, reject) { console.log('2, time = ' + new Date().toString()) resolve(); console.log('3, time = ' + new Date().toString()) }).then(microCallback); function macroCallback() { console.log('4, time = ' + new Date().toString()) } function microCallback() { console.log('5, time = ' + new Date().toString()) }
结合第二节与第三节的分析,此处的执行流程应为:
同步环境:1 -> 2 -> 3
事件循环1(microCallback):5
事件循环2(macroCallback):4
运行结果如下:
运行结果与预期一致,验证了在不同类型的任务队列中,microtask queue中的callball将优先执行。
总结:由此我们了解事件循环的机制,同时了解了任务队列、JS主线程、异步操作之间的相互协作;同时认识了两种任务队列:macrotask queue、microtask queue,它们由不同的标准制定,microtask queue对应ECMAScript的promise属性(ES6),文中说明了两者在事件循环中的运行情况及区别;在今后的异步操作中,通过灵活运用不同的任务队列,提升用户交互性能,给出更加的响应和视觉体验;同时,通过JS的事件循环机制,可以更清楚JS代码的执行流,从而更好的控制代码,更有效、更好的为业务服务。
原文链接http://www.cnblogs.com/hity-tt/p/6733062.html
相关文章推荐
- JS 事件循环机制 - 任务队列、web API、JS主线程的相互协同
- JS 事件循环机制 - 任务队列、web API、JS主线程的相互协同
- JS 的线程、事件循环、任务队列简介
- JS 的线程、事件循环、任务队列简介
- JS 的线程、事件循环、任务队列简介
- 【JavaScript 学习--12】JS深入理解调用栈,事件循环机制,回调队列
- JS 的线程、事件循环、任务队列简介
- Js事件循环机制(下)
- node.js中的事件循环机制
- 总结:JavaScript异步、事件循环与消息队列、微任务与宏任务
- javascript线程,任务队列和事件循环
- 事件循环与任务队列
- Node.js 的异步机制由事件和回调函数——循环中的回调函数
- node.js入门 - 5.事件循环机制(event loop)
- 事件循环和任务队列
- js运行机制—事件循环(Event Loop)详解
- js事件循环机制(一)
- js事件循环机制(二)
- 实例分析js事件循环机制
- Js事件循环机制(上)