JS 微任务 宏任务 变量声明var let 在循环中的区别浅析

为什么把微任务宏任务和变量声明var、let放一起,因为正好在研究循环这里,同时看到var和let在循环中的区别,就放在一起了

一、微任务宏任务

首先微任务和宏任务是JavaScript循环事件异步调用中的定义,并在ES6中分别定义为jobs和task

什么是宏任务?

    宏任务就是由宿主发起的任务

什么是微任务?

    微任务是由JavaScript引擎线程发起的任务

那什么是宿主?

    宿主即为JavaScript的运行环境,浏览器和node

    这里顺便提一嘴,node环境在版本11以下和浏览器是有区别的,11以上没细研究。相关内知识可以参考:https://blog.csdn.net/Fundebug/article/details/86487117

接下来上张流程图让我们理解下循环事件中,微任务和宏任务的执行顺序(图片来源:https://www.cnblogs.com/wangziye/p/9566454.html

接着,我们了解下哪些是宏任务,哪些是微任务

上 一段 代码 及 控制台输出

for (var index = 0; index < 2; index++) {
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)
        Promise.resolve().then(() => {
          console.log('微任务')
          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)
        })
      }

(错误理解)本来按照我对图的理解,输出是这样的:(错误:一个循环一次,先微后宏)

微任务,微任务->宏任务,宏任务->微任务,宏任务,微任务,微任务->宏任务,宏任务->微任务,宏任务

实际上是这样的

为什么会出现这么大的偏差呢?

那是因为不清楚JS的执行机制,不清楚宏任务和微任务对栈的处理机制是不同的。

JS的执行是栈结构,先进后出原则

宏任务和微任务都是栈,宏任务是可以存在多个栈的,但微任务只有一个栈,所以宏任务是一个一个执行的,微任务是一队一队执行的

接下来我们根据现有的知识再梳理下

首先我们要判定微任务宏任务执行顺序,我们需要理清整体代码的执行顺序

为了有助于理解,我们将for循环拆分,整体写一下方便理解:(并利用代码缩减法一步步理解,不正规哈~)

        //第一次
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)
        Promise.resolve().then(() => {
          console.log('微任务')
          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)
        })
        //第二次
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)
        Promise.resolve().then(() => {
          console.log('微任务')
          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)
        })

1.将整体代码的两个微任务执行,打印"微任务,微任务"

2.此时可以将代码缩减,如下图。无微任务,执行第一个宏任务,打印宏任务。

        //第一次
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)

          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)

        //第二次
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)

          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)

3此时剩余代码如图,出现微任务,执行微任务,打印'宏任务->微任务'。紧接着执行下一个宏任务,打印'微任务->宏任务'。以此类推,不难推出打印结果

        //第一次
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })

          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)

        //第二次
        setTimeout(() => {
          console.log('宏任务')
          new Promise((resolve, reject) => {
            console.log('宏任务->微任务')
          }).then(() => {
            console.log('end')
          })
        }, 0)

          setTimeout(() => {
            console.log('微任务->宏任务')
          }, 0)

二、var和let

直接上代码,代码比较简单。然后在解释其中的原理

      for (let index = 0; index < 2; index++) {
        setTimeout(() => {
          console.log('index', index)//打印0,1
        }, 0)
      }
      console.log('index', index)//报错ReferenceError: index is not defined
     for (var index = 0; index < 2; index++) {
        setTimeout(() => {
          console.log('index', index)//打印2,2
        }, 0)
      }
      console.log('index', index)//打印2

根据打印结果,有三个个问题。

1.为什么setTimeout会等循环结束执行?(会写个单章,这里涉及的是异步的运行机制,以及JS的运行机制)

setTimeout是异步函数;js是单线程的,异步会等主线程内的同步函数执行完毕才会执行异步函数,异步函数被扔到主线程外的任务中

2.var声明的index在循坏外不报错?

var存在声明提升,导致迭代变量渗透到循环外部

3.为什么let声明的和var声明的index在setTimeout中的打印结果不同

let存在块级作用域,每个迭代变量都是个新对象

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值