JS的事件循环机制

JS的事件循环机制

一、JS的运行机制

1.1 简介

JavaScript是一门单线程 语言,而单线程就意味着在一个时间点内只能做一件事情,这样就造成了这门语言的一些局限性。举个例子:如果按照单线程同步的方式运行时,当一个页面加载时向后端请求接口数据,等待数据从服务器返回的过程中,页面会呈现空白屏幕的效果。因为JavaScript是单线程,这就导致页面加载阻塞,后面的结构代码无法运行。但是在实际的网站打开时很少会发现页面假死的现象,这些都要归功于JavaScript的事件处理机制

1.2 同步与异步的产生原因

上面简介说过了JS是单线程的,同一时间只能做一件事,这样的话JS引擎就会有很多空余的时间;那么作为JS语言的开发者为了解决单线程所造成的的这个问题,提出了同步异步的执行模式;

1.3 同步(阻塞)

同步执行模式就是JS会严格按照原本的单线程逻辑,从上到下、从左到右的执行代码逻辑。上一个未执行完,下一个就不会执行。请看下面这个例子

let num = 0;
while(true) {
    num++;
    console.log(num)
}
// 上面是一个while死循环,永远都不会执行下面的这段代码
alert("代码执行完毕");
1.4 异步(非阻塞)

异步执行模式就是为了解决JS单线程的所带来的问题,从字面意思理解异步就是与同步相反,所以异步任务不会按照默认顺序执行。在执行JS代码时先逐行执行同步代码,遇到异步代码先将它"挂起",直到同步代码执行完毕或者特定时间后就执行异步代码。

let num = 0;
setTimeout(()=>num++,500);
console.log(num); // 0  
// 上面的setTimeout属于异步任务,所以当代码执行到第二行时会将它挂起
// 然后执行第三行代码直接输出0,而当500ms过去之后num将变为1
1.5 同步与异步总结

JS执行顺序就按照单线程模式运行,同步先执行,异步后执行。所有的异步任务都要等待当前的同步任务完成之后执行。

同步通俗讲就是:排队做核酸,前一个做完后一个才能做,最后来的人排到最后,遵从先进先出的规则;

异步通俗讲就是:去饭店点菜,由服务员记录每桌点的菜品,之后交给后厨;后厨根据菜单同时炒三桌相同的菜,最后三桌人都能同时吃到这个菜,不需要一桌一桌的做,减少等待时间。

二、JS的运行原理

2.1 JS的线程组成

通过上面的了解我们知道JS是单线程的,但是在浏览器中一个tab页面实际上是以多个线程协助操作JS单线程异步执行的,因此我们要了解具体的线程:

  • GUI渲染线程 // 识别css、js、html文件生成文档树最终绘制到屏幕上
  • JavaScript引擎线程 // 执行js代码
  • 定时器触发线程 // 监听定时器,当时间到时触发
  • http请求线程 // 接口请求
  • 事件触发线程 // 用户与界面交互时触发的事件监听
  • 其他线程

通过真实的浏览器线程组成我们可以知道实际运行的JS线程并不是一个,那为什么称它为单线程语言呢?因为在JS代码运行时只存在一个活动线程,然后要实现同步异步就需要多线程切换的方式来实现,所以JS线程又可以分为主线程:执行JS代码工作线程:处理异步任务的执行

2.2 JS运行模型

在这里插入图片描述

上面根据左侧代码画出了一个简单的运行模型:首先需要说明的是setTimeout属于异步任务。左侧代码声明了四个函数然后依次执行;进入JS主线程时遇到同步代码就直接放入执行栈中执行,执行完毕后如果没有再次引用则出栈就销毁。异步代码先放入工作线程中等待;当异步代码有结果返回时就会放到任务队列中排队,同步任务执行完成之后,执行栈会在任务队列中执行异步任务。这里我们看到3比2先输出,这是因为test2中定时器是1000ms而test3是500ms,所以test3先进入任务队列先进先出

2.3 总结

根据上面的运行模型图例相信我们对于代码的同步异步执行有了一个初步的认识,其中异步任务最终都会进入到任务队列中排队等待执行,而任务队列中又将异步任务划分为宏任务微任务

三、JS中的宏任务与微任务

3.1 宏任务与微任务介绍

通过上面我们了解到异步任务首先都会进入到JS工作线程中进行等待,当有异步结果返回时进入任务队列任务队列 中的异步任务⼜分为【宏任务】和【微任务】。

3.2 宏任务

宏任务是JS最先产生异步任务,包括setTimeout、setInterVal、AJAX等,在代码主线程中按照同步代码的顺序,逐个进⼊⼯作线程挂起,再按照异步任务到达的时间节点,逐个进⼊异步任务队列,最终按照队列中的 顺序进⼊函数执⾏栈进⾏执⾏。

3.3 微任务

微任务是新提出的异步任务,微任务在异步任务队列的基础上增加了微任务的概念,每⼀个宏任务执⾏前,程序会先检测中是否有当次事件循环未执⾏的微任务,优先清空本次的微任务后,再执⾏下⼀个宏任务,每⼀个宏任务内部可注册当次任务的微任务队列,再下⼀个宏任务执⾏前运⾏,微任务也是按照进⼊队列的顺序执⾏的。

3.4 常见的宏任务与微任务
宏任务微任务
整个script标签MutationObserver(浏览器)
I/O操作process.nextTick(node)
setTimeoutPromise
setIntervalPromise.then Promise.catch finally
setImmediate(node环境下)async await
requestAnimationFrame(浏览器)
3.5 总结

JS代码执行流程:

  1. 默认的同步代码按照顺序从上到下,从左到右运⾏,运⾏过程中将异步任务存放到工作进程中
  2. 注册本次的微任务和后续的宏任务
  3. 执⾏本次同步代码中注册的微任务,并向任务队列注册微任务中包含的宏任务和微任务
  4. 将下⼀个宏任务开始前的所有微任务执⾏完毕
  5. 执⾏最先进⼊队列的宏任务,并注册当次的微任务和后续的宏任务,宏任务会按照当前任务队列的队尾继续向 下排列
js事件循环机制是一种用于管理和执行任务的机制。在js中,事件循环机制负责处理用户交互事件、异步操作和定时任务等。 事件循环机制的核心是事件循环和任务队列。当有事件发生时(如用户点击按钮),事件被加入到任务队列中。js引擎会持续地从队列中取出任务并执行,直到队列为空。 任务分为两种类型:宏任务和微任务。宏任务包括用户交互事件、定时任务等,而微任务主要是由Promise对象的then方法产生的任务。在每次事件循环中,js首先执行当前宏任务,然后执行所有微任务,然后对页面进行重绘和渲染,然后进入下一次事件循环事件循环机制的重要性在于处理js的异步操作。当遇到一个异步操作时,如网络请求或定时器,js引擎不会立即执行异步任务,而是将其放入任务队列,等到主线程上的任务执行完成后再处理。这就使得js可以同时处理多个任务,提高了程序的性能和响应速度。 需要注意的是,js是单线程执行的,即每次只能执行一个任务。所以当一个任务执行时间过长时,就会造成页面的卡顿和无响应。因此,我们需要合理地使用事件循环机制,将耗时的任务分解为小块的异步任务,以保证页面正常运行和用户体验。 总而言之,js事件循环机制是一种用于管理和执行任务的机制,它通过任务队列和事件循环的方式,实现了js的异步处理,提高了程序的性能和响应速度。掌握事件循环机制对于编写高效并且流畅的js代码是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值