关于异步方法中的宏任务与微任务

前言

提示:我们都知道js是一个单线程,里面的的请求方式分为两种,一种是同步请求,一种是异步请求,同步方法先执行完毕,然后再去异步任务队列中查看有没有异步任务,有才会执行。


1.相关示例

关于异步任务呢,又区分为两种【宏任务、微任务】,接下来让我们详细的了解两种的执行顺序与区别。

代码如下(示例):

<script>
    console.log('1') 
    setTimeout(function () { 
       console.log('2')
    });
    new Promise(function (resolve) { 
        console.log('3');  
        resolve();
    }).then(function () { 
        console.log('4')
        setTimeout(function () {
            console.log('5') 
        });
    });
    new Promise(function (resolve) {
            console.log('6'); 
            resolve();
        }).then(function () {
             console.log('7')
        setTimeout(function () {
            console.log('8') 
        }); 
    });
</script>

2.代码解析

关于上面这段代码的执行顺序及最后的日志打印结果,会让好多不熟悉【宏任务、微任务】执行顺序的小伙伴看的一脸懵逼,我第一次看到觉得最后的打印结果应该是1, 2, 3, 4, 6, 7, 5, 8,看到最后的输出结果,才开始正视这个问题,看了许多相关案例,才了解一些皮毛

解析之前我们首先要知道常见的‘宏任务’和‘微任务’有哪些,
常见的微任务有:process.nextTick、Promise和 MutationObserver(监听DOM变化的事件)
常见的宏任务有:setTimeout、setInterval、setImmediate、 script标签中包含整体的代码块、 I/O操作、 UI渲染等。
关于两者之间的区别:微任务是批量执行、宏任务则是一个一个的执行。
了解完这些我们就可以上面的代码了

这里我们可以看到,script标签包含的下面的代码块,那么这就属于是第一个异步任务,也就是宏任务,首先去执行它
<script>
   // 这里我们都可以看到,宏任务第一次执行,第一次的日志输出(1),
   //这里相信大家都能看懂,接下来我们往下面看
    console.log('1') 

   //执行到这里的时候,有的同学可能会问了,不是应该正常输出(2)吗?其实不然,我们知道,
   //第一次执行完上面的宏任务了,此时呢,会先去异步任务队列中查找有没有需要执行的微任务,所以此时先跳过它,我们接着往下走
    setTimeout(function () { 
       console.log('2')
    });
    
    //我们通过上面了解到Promise是属于微任务中的,所以这里会执行第一个Promise对象
    new Promise(function (resolve) { 
    
        //执行new Promise,正式执行第二次打印输出(3)
        console.log('3');  
        
        //这里resolve()执行,改变了promise对象的状态
        resolve();
        
        //那么这里会正常执行第三次输出吗?其实不是,promise执行后,改变执行状态(成功 or 失败)后,
        //我们可以通过.then等相关方法获取到promise对象的执行结果,所以这里直接将一整块的代码块,
        //同时丢入微任务队列中,其中也包含setTimeout,继续往下看
    }).then(function () { 
       
        console.log('4')
        setTimeout(function () {
            console.log('5') 
        });
    });

       //又一个promise对象,不用说了,属于微任务
     new Promise(function (resolve) {
    
            //执行new Promise,正式执行第三次打印输出(6)
            console.log('6'); 
            
            //这里和上面一样resolve()执行,改变了promise对象的状态
            resolve();
           
           //这里不用看了,.then方法监听promise对象的执行结果,属于是微任务,将一整块代码块,
           //包含setTimeout一起丢进微任务队列中,那么接下来你会问了,看代码书写顺序,微任务执行完了,应该执行宏任务了吧?
           //其实不对,我们想一下,第一个promise对象是不是执行完毕,.then的时候将一些代码块丢进微任务队列中了?
           //是不是应该把微任务队列中的任务也执行呢?是的...就是这样...我们往回看,第一次.then()监听的地方
        }).then(function () {
             console.log('7')
             
         setTimeout(function () {
            console.log('8') 
         }); 
    });
</script>





<script>
    console.log('1') 
    setTimeout(function () { 
       console.log('2')
    });
    new Promise(function (resolve) { 
        console.log('3');  
        resolve();
    
    //看这里,看这里,第二个promise对象已经执行了,正常输出了第三次打印(6),接下来我们上面说了,
    //此时还需要查看微任务队列中有没有需要执行的微任务,这时我们就发现了,第一个promise对象的.then()监听时,
    //将这一整块代码都丢进微任务队列中了,这时我们需要做的就是执行这一块代码。
    }).then(function () { 
    
       // 监听第一次promise的执行结果,正式输出第四次打印(4)
        console.log('4')
         
         //到这里有同学会问了,这肯定该执行下面的输出了把?别着急,往下看
        setTimeout(function () {
            console.log('5') 
        });
    });


     new Promise(function (resolve) {
            console.log('6'); 
            resolve();
            
         //看这里,这里的.then()也是属于微任务队列中的,我们还需要执行它的
        }).then(function () {
            // 监听第二次promise的执行结果,正式输出第五次打印(7),此时整个微任务队列任务都执行完成了,
            //此时我们要做的就是查看异步队列中有没有需要执行的宏任务,按照代码的执行顺序,我们往上翻
             console.log('7')
             
         setTimeout(function () {
            console.log('8') 
         }); 
    });
</script>





<script>
    console.log('1') 
    
   //找到了,setTimeout属于是宏任务中的一种
    setTimeout(function () { 
    
       //正式执行第六次打印,日志输出(2),接下来要做什么呢?宏任务执行完了,
       //现在我们需要做的是去查看异步任务队列中,有没有需要执行的微任务,当前代码块并没有微任务,继续往下找
       console.log('2')
       
       //代码整个的执行了,发现在setTimeout中并没有需要执行的微任务
    });
    new Promise(function (resolve) { 
        console.log('3');  
        resolve();
    }).then(function () { 
        console.log('4')
        
       // 没有需要执行的微任务,此时我们再去执行这个宏任务
        setTimeout(function () {
        
            // 正式输出第七次打印,日志输出(5)
            console.log('5') 
            
           // 宏任务执行完成了,我们需要做的还是去查看微任务队列中有没有需要执行的微任务,如果有,
           //批量执行,当前代码块并没有
        });
    });


     new Promise(function (resolve) {
            console.log('6'); 
            resolve();
        }).then(function () {
             console.log('7')  
         
         //执行到这里了,还是没有微任务,那就执行这个宏任务 
         setTimeout(function () {
         
            //正式输出第八次打印,输出日志(8)
            console.log('8') 
            
            //执行完宏任务了,再次查看有没有需要执行的微任务,发现此时还是没有微任务,
            //那就找一下有没有宏任务吧,此时整个异步队列中,宏任务、微任务全部执行完成了

         }); 
    });
</script>



此时我们打开浏览器,看一下控制台,最后的打印结果为: 1、3、6、4、7、2、5、8

总结


以上就是今天要讲的内容,本文仅仅简单介绍了异步方法中‘宏任务’和‘微任务’的区别,大家第一次了解可能不是那么好理解,多用几次就好了,谁还不是踩着坑过来的;

关于js中事件执行的流程:
第一步:先执行所有的同步队列中的同步任务
第二步:执行完毕再去执行第一个宏任务
第三步:执行完毕第一个宏任务,再去‘微任务’队列中查看,有没有需要执行的‘微任务’,如果有,批量执行,没有就执行下一个‘宏任务’
第四步: 执行完第一批‘微任务’,此时去执行第二个宏任务
第五步:执行完宏任务,再去‘微任务’队列中查看有没有‘微任务’,如果有,批量执行,没有在执行下一个宏任务
大致就是这样一个流程,大家记住一句话就行‘有微则微,无微则宏

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值