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一些不错的函数脚本代码
Sep 10 Javascript
ExtJS4 组件化编程,动态加载,面向对象,Direct
May 12 Javascript
JS获取元素多层嵌套思路详解
May 16 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
Mar 22 Javascript
vue devtools的安装与使用教程
Aug 08 Javascript
微信小程序实现登录注册tab切换效果
Dec 29 Javascript
使用react render props实现倒计时的示例代码
Dec 06 Javascript
vue 自动化路由实现代码
Sep 03 Javascript
vue引用外部JS的两种种方法
Jan 28 Javascript
Vue自定义render统一项目组弹框功能
Jun 07 Javascript
基于Vue.js+Nuxt开发自定义弹出层组件
Oct 09 Javascript
详解JS ES6编码规范
May 07 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实现的多彩标签效果代码分享
2014/08/21 PHP
php出现web系统多域名登录失败的解决方法
2014/09/30 PHP
Thinkphp多文件上传实现方法
2014/10/31 PHP
用PHP将Unicode 转化为UTF-8的实现方法(推荐)
2017/02/08 PHP
屏蔽鼠标右键、Ctrl+n、shift+F10、F5刷新、退格键 的javascript代码
2007/04/01 Javascript
JavaScript入门教程(2) JS基础知识
2009/01/31 Javascript
向左滚动文字 js代码效果
2013/08/17 Javascript
jQuery jcrop插件截图使用方法
2013/11/20 Javascript
Javascript进制转换实例分析
2015/05/14 Javascript
js实现跨域的4种实用方法原理分析
2015/10/29 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
2016/01/28 Javascript
纯原生js实现贪吃蛇游戏
2020/04/16 Javascript
Vue三种常用传值示例(父传子、子传父、非父子)
2018/07/24 Javascript
浅谈angular2子组件的事件传递(任意组件事件传递)
2018/09/30 Javascript
Vue和React组件之间的传值方式详解
2019/01/31 Javascript
vue中使用WX-JSSDK的两种方法(推荐)
2020/01/18 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
[51:26]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第二局
2016/03/03 DOTA
简单介绍Python中的JSON使用
2015/04/28 Python
python创建列表并给列表赋初始值的方法
2015/07/28 Python
Python中subprocess的简单使用示例
2015/07/28 Python
Python学习小技巧之列表项的拼接
2017/05/20 Python
django加载本地html的方法
2018/05/27 Python
详解通过API管理或定制开发ECS实例
2018/09/30 Python
python匹配两个短语之间的字符实例
2018/12/25 Python
python3 小数位的四舍五入(用两种方法解决round 遇5不进)
2019/04/11 Python
Python3如何判断三角形的类型
2020/04/12 Python
python3判断IP地址的方法
2021/03/04 Python
优秀毕业生自我鉴定
2014/02/11 职场文书
经营目标管理责任书
2014/07/25 职场文书
2014年有孩子的离婚协议书范本
2014/10/08 职场文书
12.4全国法制宣传日活动总结
2014/11/01 职场文书
分居协议书范本(律师见证版)
2014/11/26 职场文书
2019通用版劳动合同范本!
2019/07/11 职场文书
python图片灰度化处理的几种方法
2021/06/23 Python
防止web项目中的SQL注入
2021/12/06 MySQL