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 相关文章推荐
关于js拖拽上传 [一个拖拽上传修改头像的流程]
Jul 13 Javascript
Angularjs中的事件广播 —全面解析$broadcast,$emit,$on
May 17 Javascript
jquery遍历table的tr获取td的值实现方法
May 19 Javascript
JS中使用变量保存arguments对象的方法
Jun 03 Javascript
关于Function中的bind()示例详解
Dec 02 Javascript
Bootstrap基本样式学习笔记之表单(3)
Dec 07 Javascript
Bootstrap Img 图片样式(推荐)
Dec 13 Javascript
vue.js树形组件之删除双击增加分支实例代码
Feb 28 Javascript
详解Angular4中路由Router类的跳转navigate
Jun 09 Javascript
node使用Mongoose类库实现简单的增删改查
Nov 08 Javascript
手把手教你 CKEDITOR 4 扩展插件制作
Jun 18 Javascript
Vue中的transition封装组件的实现方法
Aug 13 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动态生成VRML网页
2006/10/09 PHP
PHP使用JSON和将json还原成数组
2015/02/12 PHP
php自定义函数实现统计中文字符串长度的方法小结
2017/04/15 PHP
laravel5.0在linux下解决.htaccess无效和去除index.php的问题
2019/10/16 PHP
jquery.blockUI.js上传滚动等待效果实现思路及代码
2013/03/18 Javascript
js中substring和substr的详细介绍与用法
2013/08/29 Javascript
jQuery实现左右切换焦点图
2015/04/03 Javascript
jQuery实现径向动画菜单效果
2015/07/17 Javascript
js实现网页多级级联菜单代码
2015/08/20 Javascript
jQuery弹簧插件编写基础之“又见弹窗”
2015/12/11 Javascript
FullCalendar日历插件应用之数据展现(一)
2015/12/23 Javascript
一种新的javascript对象创建方式Object.create()
2015/12/28 Javascript
nodejs基础知识
2017/02/03 NodeJs
ztree实现权限横向显示功能
2017/05/20 Javascript
JavaScript注册时密码强度校验代码
2017/06/30 Javascript
详解JS中的this、apply、call、bind(经典面试题)
2017/09/19 Javascript
基于jQuery实现无缝轮播与左右点击效果
2018/05/13 jQuery
基于layui数据表格以及传数据的方式
2018/08/19 Javascript
js实现无限层级树形数据结构(创新算法)
2020/02/27 Javascript
js实现限定范围拖拽的示例
2020/10/26 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
[00:42]《辉夜杯》—职业组预选赛12月3日15点 正式打响
2015/12/03 DOTA
[51:26]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第二局
2016/03/03 DOTA
python django事务transaction源码分析详解
2017/03/17 Python
解决Python使用列表副本的问题
2019/12/19 Python
python_mask_array的用法
2020/02/18 Python
利用Python如何画一颗心、小人发射爱心
2021/02/21 Python
HTML5自定义data-* data(obj)属性和jquery的data()方法的使用
2012/12/13 HTML / CSS
HTML5实现签到 功能
2018/10/09 HTML / CSS
澳大利亚领先的在线美容商店:Facial Co
2017/10/22 全球购物
感恩节活动策划方案
2014/05/16 职场文书
安全标兵事迹材料
2014/08/17 职场文书
党员干部廉洁自律承诺书
2015/04/28 职场文书
python实现Nao机器人的单目测距
2021/09/04 Python
使用python创建股票的时间序列可视化分析
2022/03/03 Python
MySQL外键约束(Foreign Key)案例详解
2022/06/28 MySQL