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 Function类型
Dec 04 Javascript
理解JAVASCRIPT中hasOwnProperty()的作用
Jun 05 Javascript
使用JQUERY进行后台页面布局控制DIV实现左右式
Jan 07 Javascript
Angularjs中使用layDate日期控件示例
Jan 11 Javascript
微信小程序实现移动端滑动分页效果(ajax)
Jun 13 Javascript
Vue.js结合Ueditor富文本编辑器的实例代码
Jul 11 Javascript
JavaScript引用类型RegExp基本用法详解
Aug 09 Javascript
Javascript中的this,bind和that使用实例
Dec 05 Javascript
微信小程序 自定义弹窗实现过程(附代码)
Dec 05 Javascript
Vue的v-model的几种修饰符.lazy,.number和.trim的用法说明
Aug 05 Javascript
vue-cli3配置favicon.ico和title的流程
Oct 27 Javascript
vue浏览器返回监听的具体步骤
Feb 03 Vue.js
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的ddos攻击解决方法
2015/01/08 PHP
thinkPHP框架动态配置用法实例分析
2018/06/14 PHP
用php实现分页效果的示例代码
2020/12/10 PHP
JavaScript中的Location地址对象
2008/01/16 Javascript
js 完美图片新闻轮转效果,腾讯大粤网首页图片轮转改造而来
2011/11/21 Javascript
JavaScript 验证码的实例代码(附效果图)
2013/03/22 Javascript
浅谈JavaScript函数节流
2014/12/09 Javascript
Jquery-1.9.1源码分析系列(十一)之DOM操作
2015/11/25 Javascript
js与jQuery实现checkbox复选框全选/全不选的方法
2016/01/05 Javascript
JavaScript中Form表单技术汇总(推荐)
2016/06/26 Javascript
js原生日历的实例(推荐)
2017/10/31 Javascript
浅析Vue.js中v-bind v-model的使用和区别
2018/12/04 Javascript
vue element 生成无线级左侧菜单的实现代码
2019/08/21 Javascript
javascript递归函数定义和用法示例分析
2020/07/22 Javascript
JavaScript中Object、map、weakmap的区别分析
2020/12/15 Javascript
[08:08]2014DOTA2国际邀请赛中国区预选赛精彩TOPPLAY
2014/06/25 DOTA
Python socket.error: [Errno 98] Address already in use的原因和解决方法
2014/08/25 Python
将Django框架和遗留的Web应用集成的方法
2015/07/24 Python
Python中turtle作图示例
2017/11/15 Python
Pycharm无法使用已经安装Selenium的解决方法
2018/10/13 Python
Python计算库numpy进行方差/标准方差/样本标准方差/协方差的计算
2018/12/28 Python
Python使用Pandas库实现MySQL数据库的读写
2019/07/06 Python
python实现批量转换图片为黑白
2020/06/16 Python
Myholidays美国:在线旅游网站
2019/08/16 全球购物
乐高西班牙官方商店:LEGO Shop ES
2019/12/01 全球购物
Calphalon美国官网:美国顶级锅具品牌
2020/02/05 全球购物
Lentiamo丹麦:购买便宜的隐形眼镜
2021/01/13 全球购物
List、Map、Set三个接口,存取元素时,各有什么特点?
2015/09/27 面试题
公开服务承诺制度
2014/03/26 职场文书
岗位廉洁从政承诺书
2014/03/27 职场文书
市场营销战略计划书
2014/05/06 职场文书
纪念9.18事变演讲稿
2014/09/14 职场文书
房屋产权共有协议书范本
2014/11/03 职场文书
信息技术教研组工作总结
2015/08/13 职场文书
《灰雀》教学反思
2016/02/19 职场文书
GO中sync包自由控制并发示例详解
2022/08/05 Golang