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 相关文章推荐
自己开发Dojo的建议框架
Sep 24 Javascript
javascript 关于# 和 void的区别分析
Oct 26 Javascript
简洁短小的 JavaScript IE 浏览器判定代码
Mar 21 Javascript
jQuery 拖动层(在可视区域范围内)
May 24 Javascript
关于图片的预加载过程中隐藏未知的
Dec 19 Javascript
jquery 文本上下无缝滚动,鼠标放上去就停止 小例子
Jun 05 Javascript
使用jquery操作session方法分享
Jan 22 Javascript
使用JavaScript刷新网页的方法
Jun 04 Javascript
jQuery实现鼠标划过添加和删除class的方法
Jun 26 Javascript
JS原型、原型链深入理解
Feb 27 Javascript
JavaScript 实现自己的安卓手机自动化工具脚本(推荐)
May 13 Javascript
vue element 关闭当前tab 跳转到上一路由操作
Jul 22 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 各种排序算法实现代码
2009/08/20 PHP
PHP获取搜索引擎关键字来源的函数(支持百度和谷歌等搜索引擎)
2012/10/03 PHP
解析php中die(),exit(),return的区别
2013/06/20 PHP
PHP json_encode中文乱码问题的解决办法
2013/09/09 PHP
ThinkPHP实现跨模块调用操作方法概述
2014/06/20 PHP
PHP文件上传之多文件上传的实现思路
2016/01/27 PHP
PHP实现的进度条效果详解
2016/05/03 PHP
Laravel 实现添加多语言提示信息
2019/10/25 PHP
asp.net下使用jquery 的ajax+WebService+json 实现无刷新取后台值的实现代码
2010/09/19 Javascript
ajax处理php返回json数据的实例代码
2013/01/24 Javascript
Area 区域实现post提交数据的js写法
2014/04/22 Javascript
jQuery 中$(this).index与$.each的使用指南
2014/11/20 Javascript
jQuery关键词说明插件cluetip使用指南
2015/04/21 Javascript
AngularJS中的Directive实现延迟加载
2016/01/25 Javascript
input 禁止输入特殊字符的四种实现方式
2016/08/24 Javascript
完美解决手机网页中输入框被输入法遮挡的问题
2017/12/19 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
vue2.0+vue-dplayer实现hls播放的示例
2018/03/02 Javascript
Node.js 使用AngularJS的方法示例
2018/05/11 Javascript
JavaScript函数式编程(Functional Programming)组合函数(Composition)用法分析
2019/05/22 Javascript
python中文乱码的解决方法
2013/11/04 Python
Python开发的单词频率统计工具wordsworth使用方法
2014/06/25 Python
python中的内置函数getattr()介绍及示例
2014/07/20 Python
Python简单实现安全开关文件的两种方式
2016/09/19 Python
python+selenium+autoit实现文件上传功能
2017/08/23 Python
python使用pycharm环境调用opencv库
2018/02/11 Python
利用Python模拟登录pastebin.com的实现方法
2019/07/12 Python
CSS3 box-sizing属性详解
2016/11/15 HTML / CSS
使用css如何制作时间ICON方法实践
2012/11/12 HTML / CSS
DogBuddy荷兰:找到你最完美的狗保姆
2019/04/17 全球购物
Linux机考试题
2015/10/16 面试题
大学生秋游活动方案
2014/02/17 职场文书
2015年信息宣传工作总结
2015/05/26 职场文书
一波干货,会议主持词开场白范文
2019/05/06 职场文书
手把手教你使用TensorFlow2实现RNN
2021/07/15 Python
分享很少见很有用的SQL功能CORRESPONDING
2022/08/05 MySQL