宏任务与微任务的执行顺序

1.同步任务和异步任务
JavaScript是单线程执行的语言,在同一个时间只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS中出现了同步任务和异步任务。

(1)同步任务
在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。

(2)异步任务
不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以者种机制被叫做事件循环(Event Loop)

2.宏任务与微任务
我们会发现异步任务种的事件并不是严格按照顺序来执行的,如下:

       setTimeout(() => {
            console.log("定时器");
        }, 0);
        Promise.resolve().then(value=>{
             console.log('Promise');
        })
        console.log('console');

执行结果为:
在这里插入图片描述
这时我们就会发现任务队列中的任务是有优先级的,上文中的代码Promise的优先级高于setTimeout。再往下探索发现,任务队列中的任务也是分为两种,宏任务和微任务。

常见的微任务有Promise、process.nextTick、MutationObserver

常见的宏任务:script、setTimeout、setInterval、setImmediate
在这里插入图片描述

面试官:到底是宏任务优先还是微任务优先?(微任务优于宏任务)

在这里插入图片描述
在这里插入图片描述

Event Loop执行顺序为:
先执行宏任务script,并执行里面的同步任务;执行栈为空后查询是否存在微任务,存在就立即执行,然后开始下一轮的事件循环。

从上面的执行顺序可知,如果宏任务中有大量的计算并且需要操作DOM的话,为了更快响应,可以把操作DOM放进微任务务中。
3.定时器
定时器在开发中经常能用到,一个是超时调用定时器setTimeout(),也叫做爆炸定时器,另一个是间歇调用定时器setInterval()。但是在我们设置延时后会发现延时的时间和触发回调函数的时间不一样,究其原因,仍然是和执行机制有关。

首先我们知道定时器是宏任务,在定时器计时完毕后会将它的回调函数加入到任务队列中,等待下一次的事件循环。这也就是说下一次执行的定时器仅仅只是回调函数,计时已经在定时器模块中完成了。

如下代码:

       setInterval(()=>{
            console.log('计时5S');
        },5000)
        for(let i=0;i<10009;i++){
            console.log('');
        }

首先执行的是for循环,但是当for循环执行结束后会立即打印出“计时5S”两次。
4.Promise代表的微任务

 setTimeout(()=>{
            console.log('定时器');//1
        },0)
        new Promise(resolve=>{
            console.log('Promise');//2
            resolve()
        })
        .then(()=>{console.log('then')});//3
        console.log('console');//4
//输出结果:2>4>3>1

5.任务共享内存

       let i=0
        setTimeout(()=>{
            console.log(++i);//1
        },0)
        setTimeout(()=>{
            console.log(++i);//2
        },0)
//把两个定时器加入到任务队列中,执行完第一个时i自增变为1,再执行第二个定时器函数后i为2

面试题:

// 主线程(宏任务队列)

console.log('==== start ====')

// 第二个宏任务
setTimeout(function () {
    console.log('定时器')

    // 第三个宏任务
    setTimeout(function () {
        console.log('定时器中的定时器')
    },0)

    new Promise(function (resolve) {
        console.log('准备执行 for 循环111')

        for (let i = 0; i < 666; i++) {
            i == 5 && resolve()
        }
        // .then 属于微任务,第二个宏任务中的微任务
    }).then(function () {
        console.log('执行了 then 方法1111')
    })

}, 0)

console.log('==== end ====')

new Promise(function (resolve) {
    console.log('准备执行 for 循环222')

    for (let i = 0; i < 666; i++) {
        i == 5 && resolve()
    }
    // 第一个宏任务(主线程)执行完成之后就会执行这个微任务
}).then(function () {
    console.log('执行了 then 方法2222')
})

执行结果:

==== start ====
==== end ====
准备执行 for 循环222
执行了 then 方法2222
定时器
准备执行 for 循环111
执行了 then 方法1111
定时器中的定时器

async function foo() {
  console.log('foo');
}
async function bar() {
  console.log('bar	start');
  await foo();
  console.log('bar	end');
}
console.log('script	start');
setTimeout(function () {
  console.log('setTimeout');
}, 0);
bar();
new Promise(function (resolve) {
  console.log('promise	executor');
  resolve();
}).then(function () {
  console.log('promise	then');
});
console.log('script	end');

在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值