JS内部事件机制之单线程原理


Posted in Javascript onJuly 02, 2018

任务队列

主线程:正在执行的代码,会生成函数调用栈。

  • macro-task(宏任务,新名:task)包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
  • micro-task(微任务,新名:jobs)包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性,队列中只能有一个)

任务分类

同步任务,语句只按语句先后顺序执行,前面未执行完,不会执行后面语句。

异步任务,语句不在语句先后顺序上执行,执行到该代码时,加入到相应任务队列,延后执行。

单线程

主线程从 script (整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的 jobs。当所有可执行的 jobs 执行完毕之后。循环再次从 task 开始,找到其中一个任务队列执行完毕,然后再执行所有的 jobs,这样一直循环下去。

注意事项

  • setTimeout 最小间隔不能低于 4 毫秒,否则会自动增加。
  • DOM 的渲染每 16 毫秒执行一次,因为显示器是 60 Hz,16ms 刷新一次。
  • process.nextTick 任务会在 jobs 里单独维护一个队列,并且在其他 jobs 任务之前执行。
  • 冒泡事件会直接在子元素事件执行完成后,插入在主线程中。如果主线程不为空,那么会优先于 jobs 执行。

经典示例

示例详解:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

通过鼠标点击

<div class="outer">
 <div class="inner"></div>
</div>
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function() {
 console.log('mutate');
}).observe(outer, {
 attributes: true
});
// Here's a click listener…
function onClick() {
 console.log('click');
 setTimeout(function() {
  console.log('timeout');
 }, 0);
 Promise.resolve().then(function() {
  console.log('promise');
 });
 outer.setAttribute('data-random', Math.random());
}
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
// 输出结果
click
mutate
click
mutate
promise
promise
timeout
timeout

进阶--通过js执行

<div class="outer">
 <div class="inner"></div>
</div>
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function() {
 console.log('mutate');
}).observe(outer, {
 attributes: true
});
// Here's a click listener…
function onClick() {
 console.log('click');
 setTimeout(function() {
  console.log('timeout');
 }, 0);
 Promise.resolve().then(function() {
  console.log('promise');
 });
 outer.setAttribute('data-random', Math.random());
}
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
inner.click();
// 输出结果
click
click
mutate
promise
promise
timeout
timeout

由于点击事件是 js 执行的,inner 的 onClick 函数执行完成时,inner.click() 语句的作用域还没有退栈,主线程调用栈不是空的,导致 jobs 队列任务不会执行,mutate 和 promise 语句都未能在事件循环中执行到。从而执行了 outer 的 onClick 函数。outer 的 onClick 函数执行完成后,inner.click() 语句才退栈,继而执行 jobs 的任务。

只有一个 mutate 是由于 jobs 队列中,只能有一个 MutationObserver 任务,第二次创建时,前一个 MutationObserver 任务没有执行,顾不再创建。

总结

以上所述是小编给大家介绍的JS内部事件机制之单线程原理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
如何确保JavaScript的执行顺序 之实战篇
Mar 03 Javascript
JS原型对象通俗&quot;唱法&quot;
Dec 27 Javascript
JavaScript中对循环语句的优化技巧深入探讨
Jun 06 Javascript
js获取会话框prompt的返回值的方法
Jan 10 Javascript
jQuery中大家不太了解的几个方法
Mar 04 Javascript
jQuery Validation PlugIn的使用方法详解
Dec 18 Javascript
javascript 产生随机数的几种方法总结
Sep 26 Javascript
Vue的watch和computed方法的使用及区别介绍
Sep 06 Javascript
vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】
Nov 08 Javascript
使用webpack搭建vue环境的教程详解
Dec 31 Javascript
如何在postman测试用例中实现断言过程解析
Jul 09 Javascript
design vue 表格开启列排序的操作
Oct 28 Javascript
JS将网址url转化为JSON格式的方法
Jul 02 #Javascript
原生JS实现列表子元素顺序反转的方法分析
Jul 02 #Javascript
JS限制输入框输入的实现代码
Jul 02 #Javascript
webpack手动配置React开发环境的步骤
Jul 02 #Javascript
Angularjs中的$apply及优化使用详解
Jul 02 #Javascript
angularjs 的数据绑定实现原理
Jul 02 #Javascript
vue 解决addRoutes动态添加路由后刷新失效问题
Jul 02 #Javascript
You might like
不错的一篇面向对象的PHP开发模式(简写版)
2007/03/15 PHP
PHP编程中的常见漏洞和代码实例
2014/08/06 PHP
CodeIgniter与PHP5.6的兼容问题
2015/07/16 PHP
浅谈PHP进程管理
2019/03/08 PHP
JavaScript初学者需要了解10个小技巧
2010/08/25 Javascript
使用GruntJS构建Web程序之Tasks(任务)篇
2014/06/06 Javascript
javascript下使用Promise封装FileReader
2016/02/19 Javascript
AngularJS 视图详解及示例代码
2016/08/17 Javascript
jquery实现一个全局计时器(商城可用)
2017/06/30 jQuery
vue表单中遍历表单操作按钮的显示隐藏示例
2019/10/30 Javascript
vue v-model的用法解析
2020/10/19 Javascript
[02:33]2014DOTA2 TI每日综述 LGD涉险晋级DK闯入胜者组
2014/07/14 DOTA
[01:15:12]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#4Newbee VS CDEC
2016/03/03 DOTA
利用python获取某年中每个月的第一天和最后一天
2016/12/15 Python
Python网络编程之TCP套接字简单用法示例
2018/04/09 Python
python字符串替换第一个字符串的方法
2019/06/26 Python
Pandas的read_csv函数参数分析详解
2019/07/02 Python
python tornado使用流生成图片的例子
2019/11/18 Python
python实现的Iou与Giou代码
2020/01/18 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
Keras官方中文文档:性能评估Metrices详解
2020/06/15 Python
详解FireFox下Canvas使用图像合成绘制SVG的Bug
2019/07/10 HTML / CSS
美国百年历史早餐食品供应商:Wolferman’s
2017/01/18 全球购物
PHP如何与mysql建立链接
2013/05/05 面试题
如何写出高性能的JSP和Servlet
2013/01/22 面试题
J2EE面试题
2016/03/14 面试题
高级工程师岗位职责
2013/12/15 职场文书
11月升旗仪式讲话稿
2014/02/15 职场文书
党员干部四风问题整改措施思想汇报
2014/10/12 职场文书
区域销售经理岗位职责
2015/04/02 职场文书
2015年幼儿园保育工作总结
2015/05/12 职场文书
2016元旦晚会主持词
2015/07/01 职场文书
《分数的意义》教学反思
2016/02/20 职场文书
react使用antd的上传组件实现文件表单一起提交功能(完整代码)
2021/06/29 Javascript
postman中form-data、x-www-form-urlencoded、raw、binary的区别介绍
2022/01/18 HTML / CSS
win10音频服务未响应怎么解决?win10音频服务未响应未修复的解决方法
2022/08/14 数码科技