JS执行机制-宏任务微任务的理解

一些概念

1.同步任务和异步任务的由来

JS的一大特点是单线程,也就是说同一时间只能做一件事,也就意味着所有任务需要排队进行。当有一段代码需要执行很久,就会影响后面代码的执行,就会导致页面卡顿,用户体验差。为了避免这个问题,就出现了异步编程,通过回调函数来存放并执行异步代码,任务也就划分为:同步任务和异步任务。

2. 同步任务,异步任务的解释

  • 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。

  • 异步任务:不进入主线程,而是进入任务队列的任务,只有等主线程任务全部执行完毕,任务队列的任务才会进入主线程执行。异步任务又分为宏任务和微任务。

3. 宏任务和微任务

  • 宏任务:script(整体代码)、setTimeout、setInterval、setImmediate(Node.js 环境)、UI事件、I/O(Node.js)

  • 微任务:promise中的.then和.catch,process.nextTick()

(Promise并不是完全的同步,在Promise中是同步任务,执行resolve或者reject回调的时候,此时是异步操作,会先将then/catch等放到异步任务中的微任务队列)

4. 执行过程

  1. 先执行所有同步任务,碰到异步任务放到任务队列中

  1. 同步任务执行完毕,开始执行当前所有的异步任务

  1. 先执行任务队列里面所有的微任务

  1. 然后执行一个宏任务

  1. 然后再执行所有的微任务

  1. 再执行一个宏任务,再执行所有的微任务·······依次类推到执行结束。

3-6的这个循环称为事件循环Event Loop

事件循环是JavaScript实现异步的一种方法,也是JavaScript的执行机制

实例理解


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');
})
async function fn() {
    await fn2();
    console.log(13);
}
function fn2() {
    console.log(14);
}
fn()
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. 执行主线程的同步代码,打印第一行的1,第2-13行是一个宏任务,放到宏任务队列,14-16是一个微任务,放入微任务队列,17-23声明了两个函数;

  1. 执行主线程的同步代码,第24行是一个函数调用,进入fn内部,fn其实是声明了一个promise,promise是同步代码,会顺序执行打印14,只有.then里面的代码会加入微任务队列里,这里相当于执行了fn2()之后,再将第19行代码加入一个微任务队列中;

  1. 回到主线程,碰到一个Promise,Promise是同步任务,.then后面的回调会加入微任务队列,所以会打印26行的7;

  1. 回到主线程,碰到一个Timeout,Timeout是宏任务,放到宏任务队列;

  1. 主线程执行完成,开始执行微任务队列内的任务,遵循先进先出的原则,因此依次打印16行的6,19行的13,29行的8;

  1. 微任务执行结束,开始执行宏任务,先执行第一个宏任务第2-13行,宏任务里面也是遵循先同步后异步,先微任务后宏任务,因此依次打印第3行的2,第8行的4,第5行的3,第11行的5;

  1. 第一个宏任务执行结束,接着执行第二个宏任务,同上,因此依次打印第32行的9,第37行的11,第34行的10,第40行的12

所以最终执行顺序为:


1
14
7
6
13
8
2
4
3
5
9
11
10
12

执行顺序的总结

  1. 先执行主线程上的同步任务,将异步任务放入队列,宏任务放入下一个宏任务队列,微任务放入微任务队列,当主线程任务执行完成之后,就按照先进先出的原则执行所有的微任务,微任务执行完成后,开始执行下一个宏任务队列

  1. 当一个宏任务执行完成,如果微任务队列有微任务,会执行完所有微任务,再执行下一个宏任务

  1. promise属于同步任务,但是promise.then()和.catch()属于微任务

  1. 简单记法:主线程同步任务 = promise > promise.then() > setTimeout

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子味的冰淇淋~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值