当前位置: 首页 > news >正文

事件轮询机制

引出闭包案例

for(var i = 0; i < 5; i++) {setTimeout(function () {console.log(i); // ?});
}
console.log('a');
// 结果是什么:?

2.事件轮询机制(Event Loop)

事件轮询(Event Loop)是一个很重要的概念,指的是计算机系统的一种运行机制。JavaScript语言就是采用的这种机制,来解决单线程运行带来的一些问题。

  1. 同步和异步任务分别进入不通的执行“场所”,同步的进入主线程,异步的进入Event Table并注册函数

  2. 当指定的事情完成时,Event Table会将这个函数移入Event Queue(事件队列/任务队列/消息队列)

  3. 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行

  4. 上述过程会不断重复,也就是常说的Event loop(事件循环)

进程:

  • 进程是指在系统中正在运行的一个应用程序,程序一旦运行就是进程。

  • 一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。

线程:

  • 线程是进程的一个实体,是进程的一条执行路径。

  • 线程是CPU独立运行和独立调度的基本单位。

任务队列:

  • 将要被执行的任务,存放在浏览器的任务队列中

单线程:

  • 每次只能干一件事

多线程:

  • 多线程是指从软件或者硬件上实现多个线程的并发技术

  • 优势:

    • 使用多线程可以把程序中占据时间长的任务放到后台去处理,如图片、视屏的下载

    • 发挥多核处理器的优势,并发执行让系统运行的更快、更流畅,用户体验更好

举例:你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。 如果你一手接电话,一手打卡, 就是多线程。 2件事的结果是一样的。。你接了电话且打了卡。

事件轮询:

  • 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)

2.1 JS是单线程还是多线程

javaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。 为什么不允许js可以实现多线程?因为如果实现了多线程,一个线程创建了一个div元素,而另外一个线程删除了这个div元素,那么这个时候浏览器应该听谁的? 所以为了避免出现这种互相冲突的操作,js从一开始就是单线程的,这就是它的核心特征。 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

2.2 任务队列

2.2.1 什么是宏任务,什么是微任务

在js的异步任务中,分为宏任务和微任务

宏任务(由宿主也就是浏览器和node引发): setTimeout,setInterval,Ajax(网络请求),DOM事件

微任务(js引擎发布的任务): Promise async/await promise本身是同步的,then/catch的回调函数是异步的

注意:微任务比宏任务的执行时间要早

2.2.2 宏任务和微任务的执行顺序
  1. 同步代码

  2. 微任务的异步代码(promise等)

  3. 宏任务的异步代码(setTimeout,setInterval等)

执行顺序

 

2.2.3 案例
console.log(1);
setTimeout(function(){console.log(2);
},100)
let pro = new Promise((resolve,reject)=>{console.log(3)resolve(1000);console.log(4)
})
pro.then(data=>{console.log(data);
})
console.log(5); // 1 3 4 5 1000 2

2.3 解决方案

  1. 使用闭包

for(var i = 0; i < 5; i++) {//这个匿名函数生成了闭包的效果,新建了一个作用域,这个作用域接收到每次循环的i值保存了下来,即使循环结束,闭包形成的作用域也不会被销毁(function(i) {setTimeout(function () {console.log(i);});})(i)
}
console.log('a');
  1. 使用let变量

for(let i = 0; i < 5; i++) {setTimeout(function () {console.log(i);});
}

3.闭包

特性:

  1. 函数嵌套函数

  2. 函数内部可以引用函数外部的参数和变量

  3. 参数和变量不会被垃圾回收机制回收【延长变量作用域】

闭包是js开发惯用的技巧:能够访问另一个函数作用域的变量的函数

清晰的讲:闭包就是一个函数,这个函数能够访问其他函数的作用域中的变量 闭包可以用在许多地方。它的最大用处有两个

  1. 一个是前面提到的可以读取函数内部的变量

  2. 另一个就是让这些变量的值始终保持在内存中。

function func1(){var num = 1;function func2(){return num;}return func2; // 闭包
}
var num = func1()();
console.log(num);

注意:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

3.1 闭包的作用

闭包可以延长作用域链

function person(name){var name = name;function sayName(){console.log(name)}return sayName;
}
var fun = person('王小明');
fun();// 王小明

fun 是一个 全局函数,但可以访问到person里的局部变量 name,这是因为fun的值是从person函数中返回的sayName函数,而sayName 函数是可以访问到局部变量 name 的;

3.2 复杂闭包案例分析

function outer(){// 局部变量var a = '我是outer里面的变量';// var c = 'one'// console.log(a);function twoinner(){var b = '我是twoinner的变量';var c = 'two'// console.log(b);return a;// function thrinner(){//     var c = '我是thrinner';//     console.log(c);// }// thrinner();// return thrinner;}return twoinner; // 函数体: twoinner函数就是一个闭包, 因为它能够访问到其他函数中的变量的作用域
}
// console.log(outer());
// console.log(outer()());
// outer()()();
var n =  outer()();
console.log(n);

3.3 闭包能够解决的问题

问题:给下面5个li添加点击事件,点击显示当前元素的下标

<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
</ul>
<script>var oli = document.getElementsByTagName('li');/* 输出的全都是5 */for(var i=0;i<oli.length;i++){oli[i].onclick = function(){console.log(i);}} 
</script>

使用闭包解决

/* 闭包方案解决: */
for(var i=0;i<oli.length;i++){oli[i].onclick = (function(i){return function(){console.log(i);}})(i); // 闭包
}

使用let解决

// let 方案解决
for(let i=0;i<oli.length;i++){oli[i].onclick = function(){console.log(i);}; // 闭包
}

分析执行过程

/* 分析执行过程 */
oli[0].onclick = (function(0){return function(){console.log(0);}
})(0);
// => 第一次循环 闭包函数自执行完毕
oli[0].onclick = function(){console.log(0);
};

3.4 闭包有三个特性:

  1. 函数嵌套函数

  2. 函数内部可以引用外部的参数和变量

  3. 参数和变量不会被垃圾回收机制回收

  4. 自执行函数

(function a(){alert('我是自执行函数')} ()); // 用括号把整个表达式包起来
(function a(){alert('我是自执行函数')}) (); //用括号把函数包起来
!function a(){alert('我是自执行函数')}(); // 求反,我们不在意值是多少,只想通过语法检查。
+function a(){alert('我是自执行函数')}();
-function a(){alert('我是自执行函数')}();
~function a(){alert('我是自执行函数')}();
void function a(){alert('我是自执行函数')}();
new function a(){alert('我是自执行函数')}();

自执行函数通常都是定义之后立即执行,以后都不再会调用,所以声明时可以省略函数名,因此自执行函数又叫匿名函数

(function(){console.log('我是匿名函数')})();// 我是匿名函数

如果上一行代码没有使用 分号 ' ; '结束,可能会导致匿名函数通不过语法检查,所以通常会在小括号前加个分号

;(function(){console.log('我是匿名函数')})()// 我是匿名函数

4.1自执行函数的效果

自执行函数可以用来保存变量的作用域,防止污染全局变量


http://www.mrgr.cn/news/48248.html

相关文章:

  • Log4j2 插件的简单使用
  • SAP抓取外部https报错SSL handshake处理方法
  • 【ETCD】ETCD 架构揭秘:内部各组件概览
  • threejs 建筑设计(室内设计)软件 技术调研之四 墙体添加真实门窗并保持原材质
  • AD18原理图快捷键与编译检查
  • 数字经济下的 AR 眼镜
  • Java数组的使用方法
  • 基于SpringBoot+Vue的超市管理系统设计实现(协同过滤算法、图形化分析)
  • 物理学基础精解【67】
  • 【jvm】垃圾回收是否会涉及到虚拟机栈?
  • 10月11日复盘日记
  • 离线使用k8s部署项目
  • thymeleaf
  • docker 安装与使用
  • 【cocos creator】输入框滑动条联动小组建
  • OpenRewrite配方之代码格式化——org.openrewrite.java.format.AutoFormat
  • 毕业设计之—基于ManTra-Net的图像篡改检测方法研究与应用实现
  • 你的拼命向前,只不过是别人的轻松实现
  • 【D3.js in Action 3 精译_033】4.1.0 DIY 实战:如何通过学习 d3.autoType 函数深度参与 D3 生态建设
  • Antsword-labs靶机渗透
  • QT:数据库,opencv
  • MySQL-02.概述-安装配置
  • 共识算法Raft
  • std::future::then的概念和使用方法
  • 让UE通过EPC连接到互联网
  • 基于JAVA+SpringBoot+Vue的医疗报销系统