目录前言引言为什么会有事件循环?js是单线程的同步任务和异步任务 JS事件循环宏任务与微任务常见的宏任务有哪些?常见的微任务有哪些?执行过程总结(重点)同步任务 &mdas
相信对于刚学习javascript的新手来说,去理解JS中的事件循环原理以及异步执行过程比较困难,但是这是JS必须要会的基础知识,逃避不能解决问题,笔者曾经也被这个知识点困扰过,现根据以往的经验编写此文章,旨在帮助大家彻底搞懂它们以及自我巩固,话不多说,进入正题。
注意:本篇文章主要是基于浏览器环境,node环境没有研究过暂不讨论
我们先来小试牛刀,看看下面这段代码是怎么执行的,例1:
setTimeout(() => {
console.log('time')
});
new Promise((resolve, reject) => {
console.log('p1');
resolve();
}).then(() => {
console.log('res')
});
console.log(1);
// 输出: p1 1 res time
怎么样?你想的输出结果和实际的输出结果是一样的吗?如果是一样的说明你对事件循环有一定的了解,但是你真的已经清楚的知道了事件循环的原理吗?让我们继续往下看。
众所周知:JavaScript 是一门单线程语言,也就是说,同一个时间只能做一件事。这是因为 Javascript 这门脚 本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对 某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 WEB Worker 标准,允许JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。于是,JS 中出现了同步任务和异步任务。
同步任务都在主线程上执行,形成一个执行栈。在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。JS 的异步是通过回调函数实现的。异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
注意:异步任务执行机制在这里描述的比较笼统,主要方便大家理解,具体细节在后面的“宏任务与微任务”中会详细介绍
JS的事件循环就是基于同步任务与异步任务来展开的,让我们继续往下看:
事件循环是JavaScript实现异步的一种方法,也是JavaScript的执行机制
如图:
当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。
当遇到异步任务时不会一直等待事件的返回结果,而是将事件挂起(即交给其他线程处理,上图是指Web Worker),继续执行执行栈中的其他任务。
当异步事件返回结果时,js将异步事件callback函数放入队列中,被放入队列中的异步事件不会立即回调,等到当前执行栈中的任务都执行完成,处于闲置状态的主线程按照队列顺序将处于首位事件的callback函数放入执行栈中,执行该函数的同步代码,如果遇到了异步事件,同样也会将其回调函数放入事件队列中…
如此反复,就形成了一个循环,这也是被称为“事件循环(EventLoop)”的原因。
js事件循环的基本原理已经描述清楚,但是异步任务之间也有所不同:
任务队列实际上分为两个:宏任务队列和微任务队列。上图只表示了一个是为了便于大家理解事件循环,下面就是事件循环更细节的东西了
上面讲到,js在执行异步任务时,回调函数会被放在js的任务队列中,实际上,回调函数的类别不同,执行的优先级也不同。
不同的优先级被分为两类,一类是宏任务(Micro task),一类是微任务(Macro task)。
回调函数是微任务时,会被放在微任务队列,回调函数是宏任务时,会被放在宏任务队列。
微任务的优先级高于宏任务,当主线程的任务执行完成时,会首先去执行微任务队列中首位的回调函数,当微任务队列中为空时,才回去执行宏任务队列中的回调函数。
注意:new Promise()属于同步任务,但是Promise.then(); Promise.cath()属于异步任务的微任务
现在我们对事件循环有了深入了解了,但是它们的执行过程还不是很清晰,我们再把执行过程弄清楚了以后就能游刃有余了。
3-6的这个循环称为事件循环Event Loop
学会了吗?让我们来做几个案例巩固一下吧
const promise = new Promise((resolve, reject) => {
resolve("10")
}).then(res => {
console.log("res1:", res) //res1: hahaha
return 9
}).then(res => {
console.log("res2:", res) //res2: 9
return 8
}).then(res => {
console.log("res3:", res) //res3: 8
let promise2=new Promise((resolve,reject)=>{
resolve("p2")
}).then(res=>{
console.log(res)
setTimeout(function(){
console.log("setTimeout2")
},0)
})
})
console.log('aaa')
setTimeout(function(){
console.log("setTimeout1")
},0)
const promise1 = new Promise((resolve, reject) => {
console.log("p1")
resolve(989)
}).then(res => {
console.log(res)
return 990
}).then(res=>{
console.log(res)
return 991
}).then(res=>{
console.log(res)
return 0
})
console.log('1');
// 定义注解 setTimeout_1 用于下文使用方便
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
// setTimeout_2
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
// 输出结果: 1 7 6 8 2 4 3 5 9 11 10 12
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
// 输出结果:1 7 6 8 2 4 3 5 9 11 10 12
以上就是JavaScript事件循环剖析宏任务与微任务的详细内容,更多关于JavaScript 事件循环宏任务微任务的资料请关注编程网其它相关文章!
--结束END--
本文标题: JavaScript事件循环剖析宏任务与微任务
本文链接: https://lsjlt.com/news/169570.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0