EventLoop 事件循环机制理解

1、首先说一下为什么会运用到事件循环机制呢?

因为 JavaScript 是单线程语言,当执行过程中遇到了非常耗时的操作时,线程中的下一个操作只能等待这个操作完成后才能执行,这样会造成页面发生卡顿,为了解决这样的问题,就出现了异步编程。

2、那异步编程是如何执行的呢?

1、js 代码执行时,浏览器会开启一个主线程,用于 js代码的执行,代码从上到下按顺序执行,遇到异步任务,只要异步任务有了运行结果,就会将其回调函数作为一个任务添加到任务队列中。

2、等主线程中的同步任务全部执行完成后,就会去任务队列中查看是否有任务,如果有,就将任务放入到主线程中执行,如果在执行过程中,又遇到了异步任务,则再次将新的回调函数放入到任务队列中,这时主线程又被占用了。

事件循环机制:不断地循环异步编程的操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IAGZrzve-1650413872387)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220419151923240.png)]

3、异步任务
(1)宏任务(Tasks)
宏任务浏览器Node
setTimeOut
setInterval
setImmediate×
requestAnimationFrame×

​ 主要记忆的:setTimeOut,setInterval,整体代码script

(2)微任务(Microtasks)
微任务浏览器Node
process.nextTick×
MutationObserver×
Promise.then catch finally

主要记忆的:Promise,process.nextTick,

注意:promise传入的执行函数会立即执行属于同步

(3)异步任务执行顺序

一般来说,微任务先于宏任务执行,执行宏任务时,遇到微任务,先执行微任务,再执行之后的宏任务

注意:不是在所有情况下,微任务都先于宏任务执行!!! 当微任务的状态不确定时,它不会被加到任务队列中,此时是任务队列中的宏任务先执行,只有等微任务的状态确定之后,它才会被加入到任务队列中,才会被执行。

事件循环机制过程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xofOP7nD-1650413872396)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220419164603353.png)]

来练练手叭~

let p1 = new Promise((resolve,reject)=>{
    console.log(1);
    setTimeout(()=>{
        resolve('ok');
        console.log('2');
    },1000);
})
p1.then((ret)=>{
    console.log('success:',ret);
},(reason)=>{
    console.log('failed:',reason);
});
console.log(3);



// 1
// 3
// 2
// success: ok  

分析:

首先会按代码顺序执行同步任务,而上文中有说到,promise传入的执行函数属于同步,所以会先执行输出 ’ 1 ’ ;然后遇到了setTimeout,把它加入到任务队列中,然后是还没有确定状态的微任务,先挂起;最后是输出 ‘ 3 ’。

执行完同步任务后,检查任务队列中有没有任务,发现有setTimeout(宏任务)存在,然后执行setTimeout,调用 resolve (‘ok’),可以知道 p1 的状态;这时将 then 的回调(微任务)加入到任务队列中;但是此时因为setTimeout还在主线程中运行,所以先输出 ‘ 2 ’ ;输出 ‘ 2 ’之后说明这次的同步执行完成啦。

接下来要去任务队列中查找任务,这时 then 的回调已经加入到队列中啦,所以要把这个微任务放到主线程中执行,最后输出了 success: ok

再来一题练练叭~(这个例子是我在网上找的,侵删)

var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

console.log('script start');

setTimeout(function s1(){
    console.log('setTimeOut1');
    Promise.resolve().then(() => {
      console.log('s1 promise');
    });
    outer.setAttribute('data1-random', Math.random());
}, 0)

new MutationObserver(function () {
  console.log('mutate');
}).observe(outer, {
  attributes: true,
});

new Promise(function p1(resolve){
    console.log('p1 start');
    setTimeout(function s2() {
      console.log('setTimeOut2');
      resolve();
      console.log('p1 end');
    },0)
}).then(function(){
    console.log('promise2');
    setTimeout(function s3(){
      outer.setAttribute('data3-random', Math.random());
      console.log('setTimeOut3');
    }, 0)
})

console.log('script end');



//script start
//p1 start
//script end
//setTimeOut1
//s1 promise
//mutate
//setTimeOut2
//p1 end
//promise2
//setTimeOut3
//mutate

分析:

首先还是先执行主线程中的同步任务,输出 ‘ script start ’ ,

setTimeout( s1)是宏任务,加入到任务队列中,

MutationObserver是微任务,但是它需要触发回调才能执行,所以先挂起;

然后到了promise传入的执行函数 p1; 输出 ‘p1 start’ ,

setTimeout(s2) 是宏任务,加入到任务队列中

因为Promise p1 还没有确认状态,所以promise(p1).then 先挂起

继续执行同步任务, 输出 ‘script end’;

主线程中同步任务执行完成后,开始查看任务队列中是否有任务,首先是 setTimeout( s1),

将setTimeout( s1)放入到主线程中,开始执行,首先输出 ‘setTimeOut1’;

触发 Promise.resolve().then(s1)回调,将 Promise.resolve().then(s1)回调函数(微任务)加入到任务队列中,因为它是微任务,所以先执行,输出 ‘ s1 promise ’;

outer.setAttribute(‘data1-random’, Math.random()触发MutationObserver() 回调函数,因为它是微任务,所以执行MutationObserver() 回调函数,输出 ‘mutate ’;

主线程执行完成后,检查任务队列,将 setTimeout( s2)放入到主线程中,开始执行,输出 ‘setTimeOut2’

resolve( ) 触发 Promise.resolve().then(s2)回调,将回调函数(微任务)加入到任务队列中,

然后继续执行主线程中同步任务,输出 ‘p1 end’

接着执行 Promise.resolve().then(s2)回调,输出 ‘promise2’ ;

setTimeout(s3)是宏任务,加入到任务队列中

主线程同步任务执行完成,检查队列中是否还有任务,将setTimeout(s3)放入到主线程中执行

outer.setAttribute(‘data1-random’, Math.random()触发MutationObserver() 回调函数,因为它是微任务,先加到任务队列中,等主线程同步任务执行完成后,才能执行,

所以输出 ‘setTimeOut3’

最后从任务队列中,将微任务放到主线程中,执行MutationObserver() 回调函数,输出 ‘mutate ’;

参考文章:

重学JS|这次聊聊EventLoop

彻底搞懂JS事件循环机制(event loop)

理解JS异步编程(二)、async、await

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值