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判断录入的日期是否合法
Jan 08 Javascript
List Information About the Binary Files Used by an Application
Jun 18 Javascript
使用js在页面中绘制表格核心代码
Sep 16 Javascript
javascript的alert box在java中如何显示多行
May 18 Javascript
Node.js与PHP、Python的字符处理性能对比
Jul 06 Javascript
解决js图片加载时出现404的问题
Nov 30 Javascript
文本溢出插件jquery.dotdotdot.js使用方法详解
Jun 22 jQuery
详解用node.js实现简单的反向代理
Jun 26 Javascript
浅谈对Angular中的生命周期钩子的理解
Jul 31 Javascript
微信小程序左滑删除功能开发案例详解
Nov 12 Javascript
vue2 中二级路由高亮问题及配置方法
Jun 10 Javascript
Vue数据双向绑定原理实例解析
May 15 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
使用Composer安装Yii框架的方法
2016/03/15 PHP
php unlink()函数使用教程
2018/07/12 PHP
常用简易JavaScript函数
2009/04/09 Javascript
javaScript 读取和设置文档元素的样式属性
2009/04/14 Javascript
window.open不被拦截的实现代码
2012/08/22 Javascript
javascript dom追加内容实现示例
2013/09/21 Javascript
jquery form 隐藏的input 选择
2014/04/29 Javascript
ff chrome和ie下全局动态定位的异同及全局高度的取法
2014/06/30 Javascript
node.js中的http.response.setHeader方法使用说明
2014/12/14 Javascript
js获取当前日期时间及其它操作汇总
2015/04/17 Javascript
Javascript中setTimeOut和setInterval的定时器用法
2015/06/12 Javascript
js时间戳转为日期格式的方法
2015/12/28 Javascript
JS中的数组转变成JSON格式字符串的方法
2017/05/09 Javascript
Vue添加请求拦截器及vue-resource 拦截器使用
2017/11/23 Javascript
jQuery实现文件编码成base64并通过AJAX上传的方法
2018/04/12 jQuery
JavaScript实现点击出现图片并统计点击次数功能示例
2018/07/23 Javascript
Ant Design Vue 添加区分中英文的长度校验功能
2020/01/21 Javascript
python超简单解决约瑟夫环问题
2015/05/12 Python
Python中的with...as用法介绍
2015/05/28 Python
关于numpy中np.nonzero()函数用法的详解
2017/02/07 Python
Django中Forms的使用代码解析
2018/02/10 Python
python使用装饰器作日志处理的方法
2019/07/11 Python
python利用tkinter实现屏保
2019/07/30 Python
通过selenium抓取某东的TT购买记录并分析趋势过程解析
2019/08/15 Python
Django之使用内置函数和celery发邮件的方法示例
2019/09/16 Python
解决Python中回文数和质数的问题
2019/11/24 Python
如何理解Python中的变量
2020/06/01 Python
纯css3实现效果超级炫的checkbox复选框和radio单选框
2014/09/01 HTML / CSS
HTML table 表格边框的实现思路
2019/10/12 HTML / CSS
简洁自适应404页面HTML好看的404源码
2020/12/16 HTML / CSS
ALDI奥乐齐官方海外旗舰店:德国百年超市
2017/12/27 全球购物
美国著名的女性内衣零售商:Frederick’s of Hollywood
2018/02/24 全球购物
周生生珠宝香港官网:Chow Sang Sang(香港及海外配送)
2019/09/05 全球购物
女大学生个人求职信
2013/12/09 职场文书
群教班子对照检查材料
2014/08/26 职场文书
合理化建议书范文
2015/09/14 职场文书