JS中的事件循环机制

javascript是一门单线程、非阻塞的语言。任何时候,都只有一个主线程来处理所有的任务。

当遇到异步事件时,并不会一直等待异步代码返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当异步事件返回结果后,js会将异步事件添加到另一个与主执行栈不同的队列,称之为异步任务队列。

被添加到异步任务队列中的回调并不会立即执行,而是会等主执行栈的任务执行完毕后,再去检查任务队列(这里的任务队列,又分为微任务和宏任务)里是否有任务。首先会去读取微任务队列(micro task)是否有事件存在,如果不存在,接着会读取宏任务队列(macro task),把宏任务队列中的事件回调,推入到主执行栈进行执行。如果存在,会依次读取微任务队列,直到所有的微任务都执行完毕,再去读取宏任务队列的事件,把其对应的回调代码推入到主执行栈中进行执行,如此反复执行,形成循环----也就是我们所说的事件循环。

为了更明确事件循环的流程,可通过 下图 或 伪代码 帮助记忆:
在这里插入图片描述
什么是事件循环(记忆伪代码):

// eventLoop是一个用作队列的数组 //(先进,先出)
var eventLoop = [ ];
var event;
//“永远”执行 
while (true) {
	// 一次tick
	if (eventLoop.length > 0) {
		// 拿到队列中的下一个事件 
		event = eventLoop.shift();
		// 现在,执行下一个事件 
		try {
			event(); 
		} catch (err) {
			reportError(err);
		} 
	}
}

宏任务(macro task) 主要包含:script、setTimeout、setInterval、I/O、UI 交互事件
微任务(micro task) 主要包含:Promise、MutaionObserver

接下来再来看我们经常遇到的面试考题:

console.log('script start');

setTimeout(function() {
  console.log('timeout1');
}, 10);

new Promise(resolve => {
    console.log('promise1');
    resolve();
    setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
    console.log('then1')
})

console.log('script end');

以上代码执行流程为:

  • 会先执行同步代码:执行console.log(‘script start’);
  • 接着遇到异步事件setTimeout,会添加到宏任务队列等待执行。
  • new Promise会立即执行,然后执行内部的console.log(‘promise1’);
  • 接着又遇到new Promise内部的异步事件setTimeout,仍然添加到宏任务队列等待执行;
  • new Promise内的代码执行完之后,会遇到promise.then异步事件,它为微任务事件,所以添加到微任务等待执行;
  • 接着又会执行下面的同步代码console.log(‘script end’);
  • 同步代码执行完毕,会先读微任务事件,这时微任务中含有promise.then(), 推入主执行栈执行,会打印 ‘then1’;
  • 微任务执行完毕,去读取宏任务中的事件,依次执行后打印 ‘timeout1’ 和 ‘timeout2’;

所以以上代码打印结果为:script start、promise1、script end、then1、timeout1、timeout2

注: 一定要清楚,setTimeout(…) 并没有把你的回调函数挂在事件循环队列中。它所做的是设定一个定时器。当定时器到时后,环境会把你的回调函数放在事件循环中,这样,在未来某个时刻的 tick 会摘下并执行这个回调。

如果这时候事件循环中已经有 20 个项目了会怎样呢? 你的回调就会等待。它得排在 其他项目后面——通常没有抢占式的方式支持直接将其排到队首。这也解释了为什么 setTimeout(…) 定时器的精度可能不高。大体说来,只能确保你的回调函数不会在指定的 时间间隔之前运行,但可能会在那个时刻运行,也可能在那之后运行,要根据事件队列的 状态而定。

?小结:微任务优先于宏任务执行,所以如果有需要优先执行的异步逻辑,可放入 micro task 队列会比 macro task 更早的被执行。

发布了54 篇原创文章 · 获赞 21 · 访问量 7207

猜你喜欢

转载自blog.csdn.net/Riona_cheng/article/details/101778206