JavaScript的执行机制是什么,事件循环是什么?

浏览器的事件循环

浏览器中的事件循环会涉及到一个任务队列(task queue)的概念。所有的异步任务执行完毕后都会将对应的回调函数放到任务队列中,并进行排队依次处理。而任务队列又分为宏任务队列微任务队列,并且只有在主线程的调用栈被清空的时候,才会执行任务队列中的任务,这也就是所谓的JavaScript的运行机制


浏览器宏任务主要有setTimeout()setInterval()
浏览器微任务主要有Promise.then()requestAnimationFrame()、process.nextTick

并且微任务优先级要高于宏任务。当主线程调用栈空闲时,就会检测任务队列中是否有任务要执行,首先看一下微任务队列中是否有任务要执行,如果有则执行微任务队列中的任务,直到微任务队列清空为止,然后接着开始执行宏任务队列中的任务,宏任务清空后,又接着检测微任务队列中是否有任务,如此往复下去形成事件循环

JS的执行机制是

事件循环第一种

  • 首先判断JS是同步还是异步,同步就进入主线程,异步就进入event table(宿主环境中)
  • 异步任务在event table中注册函数,当满足触发条件后,被推入event queue(任务队列)
  • 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主线程中

以上三步循环执行,这就是event loop

事件循环第二种

 setTimeout(function(){
     
     
     console.log('A')
 });
 
 new Promise(function(resolve){
     
     
     console.log('B');
     for(var i = 0; i < 10000; i++){
     
     
         i == 99 && resolve();
     }
 }).then(function(){
     
     
     console.log('C')
 });
 
 console.log('D');

上面代码执行结果为:B D C A

解析一下原因为什么执行循序是这样的?

这是因为异步任务又分为宏任务和微任务

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise.then,process.nextTick
  • 按照这种分类方式:JS的执行机制是 :
  • 执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
  • 当前宏任务执行完成后,会查看微任务的【事件队列】,并将里面全部的微任务依次执行完

重复以上2步骤,结合event loop(1) event loop(2) ,就是更为准确的JS执行机制了。

具体执行过程分析为:

首先执行script下的宏任务,遇到setTimeout,将其放到宏任务的【队列】里

遇到 new Promise直接执行,打印"B"

遇到then方法,是微任务,将其放到微任务的【队列里】

遇到同步任务console.log('D') 直接打印 "D"

本轮宏任务执行完毕,查看本轮的微任务,发现有一个then方法里的函数, 打印"C"

到此,本轮的event loop 全部完成。


下一轮的循环里,先执行一个宏任务,发现宏任务的【队列】里有一个 setTimeout里的函数,执行打印"A"

所以执行结果为:B D C A

看一个复杂的例子:

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')
})
})
//1 2 4 3 5 

执行过程:

1、宏任务同步代码 console.log(‘1’)

2、setTimeout,加入宏任务 Event Queue,没有发现微任务,第一轮事件循环走完

扫描二维码关注公众号,回复: 14824731 查看本文章

3、第二轮事件循环开始,先执行宏任务,从宏任务 Event Queue 中读取出 setTimeout 的回 调函数

4、同步代码 console.log(‘2’),发现 process.nextTick,加入微任务 Event Queue

5、new Promise,同步执行 console.log(‘4’),发现 then,加入微任务 Event Queue

6、宏任务执行完毕,接下来执行微任务,先执行 process.nextTick,然后执行 Promise.then

7、微任务执行完毕,第二轮事件循环走完,没有发现宏任务,事件循环结束

总结

事件循环先执行宏任务,其中同步任务立即执行,异步任务加载到对应的 Event Queue 中, 微任务也加载到对应的微任务的 Event Queue 中,所有的同步微任务执行完之后,如果发现微任 务的 Event Queue 中有未执行完的任务,先执行他们这样算是完成了一轮事件循环。接下来查看 宏任务的队列中是否有异步代码,有的话执行第二轮的事件循环,以此类推。

猜你喜欢

转载自blog.csdn.net/qq_43375584/article/details/125501525