面试之事件循环(消息队列)、宏任务、微任务、async、await原理,事件机制

面试之宏任务、微任务、async、await原理

事件循环(消息队列)

  • 事件循环,说到这里,不得不说的是,浏览器的进程与线程,由于浏览器的一个tab代表一个进程(加载静态页面)
  • 一个进程里面包含多个线程,又gui线程,js引擎线程,定时器线程,httpp线程
  • 主要的是 再浏览器的线程执行之中,js引擎为单线程的,于是会造成的是划分为几种执行机制,首先是同步任务,还有异步任务,异步任务里面分(宏任务、微任务)
  • 根据触发的机制,把对应要执行的事件,达到条件后,一一排序到 消息队列之中 等待js引擎的执行
  • 优先执行同步,然后微任务,最后是宏任务,执行消息队列之中的事件,再一次去查询是否还有未执行的事件,这就是所谓的事件循环

消息队列之宏任务、微任务

  • 1:JS引擎执行任务的时候是单线程的,也就是说一条流水线下来执行

  • 2:优先执行同步任务,异步任务放置在消息队列之中

  • 3:消息队列分为两种,宏队列(宏任务),微队列(维任务)

  • 4:微队列优先于宏队列执行,

  • 注意点1:即使两个宏队列里面,其中有一个微队列,那么就先执行宏列队后,把宏队列的微队列取出执行后,最后指向宏队列的下一个宏队列

  • 注意点2:

    • 宏队列(dom的回调函数,还有ajax,还有定时器函数)
    • 微队列(promise回调函数,还有mutation回调函数)

消息队列示例1

      console.log('1')
      setTimeout(() => {
        console.log('2')
      })
      Promise.resolve().then(() => {
        console.log('3')
      })
      console.log('4')
      // 结果是: 1 4 3 2
      // 分析:
      // log为同步任务优先执行 1 - 4
      // setTimeout为宏任务 Promise为微任务,微任务先执行,则先3 最后 2

消息队列示例2

      const home = this.$refs.home
      let li = document.createElement('li')
      li.innerHTML = '我是添加的li'
      home.insertBefore(li, home.children[0])
      console.log('1')
      setTimeout(() => {
        console.log('2')
        alert('阻断js执行 宏')
      })
      Promise.resolve().then(() => {
        console.log('3')
        alert('阻断js执行 微')
      })
      console.log('4')
      // 结果是: 1 4 3(阻断js执行 微) dom渲染(创建dom节点 li 我是添加的li) 2
      // 微任务 > dom渲染 > 宏任务
      // 分析:
      // log为同步任务优先执行 1 - 4
      // setTimeout为宏任务 Promise为微任务,微任务先执行,则先3 之后alret一个 (阻断js执行 微)
      // dom渲染出 li标签 我是添加的li 最后执行宏任务 2

消息队列3

      console.log('1')

      async function async1() {
        await async2()
        console.log('async1')
      }
      async function async2() {
        console.log('async2')
      }
      async1()

      setTimeout(function () {
        console.log('setTimeout')
      }, 0)

      new Promise(resolve => {
        console.log('Promise')
        resolve()
      })
        .then(function () {
          console.log('promise1')
        })
        .then(function () {
          console.log('promise2')
        })

      console.log('2')
      // 结果
      // // 先执行第一轮:同步任务 使用await语法之后 转化为同步任务;new Promise里面的函数为同步任务(Promise)
      // // 第一轮执行的同步任务结果 1 async2 Promise 2 async1
      // 第一轮先执行同步任务
      // 1 -> await async2() 中的async2()是同步任务,优先打印出async2,
      // 之后的代码则由于await处理后,加入微任务消息队列 -> 然后再执行;new Promise里面的函数为同步任务(Promise)
      // 最后执行最后的同步任务 2
      // 同步任务的执行结果:1 async2 Promise 2
      // 再执行微任务:async1 promise1 然后下一个.then()存储再下一个微任务之中
      // 没有其他的微任务则继续执行下一个消息队列的微任务 promise2
      // 最后执行宏任务 setTimeout
      // 最后结果:1 async2 Promise 2 async1 promise1 promise2 setTimeout

消息队列4

      setTimeout(() => {
        console.log('0')
      }, 0)

      new Promise(resolve => {
        console.log('1')
        resolve()
      })
        .then(() => {
          console.log('2')
          new Promise(resolve => {
            console.log('3')
            resolve()
          })
            .then(() => {
              console.log('4')
            })
            .then(() => {
              console.log('5')
            })
        })
        .then(() => {
          console.log('6')
        })

      new Promise(resolve => {
        console.log('7')
        resolve()
      }).then(() => {
        console.log('8')
      })
      // 执行同步任务
      // 1 -> 7 微任务消息队列[2,8]
      // 执行微任务:
      // 微任务之中 同步任务 2 -> 同步任务 3 -> 下一个消息队列[8,4]
      // 先执行8 -> 下一个消息队列[4]
      // 由于微任务5是不确定,只有等微任务4执行后才确定,因此 -> 下一个消息队列[4,6]
      // 执行微任务4之后,里面的微任务5才确定,放在下一轮消息队列之中[6,5]
      // 之后执行 6 - 5
      // 最后执行宏任务0
      // 结果 1 7 2 3 8 4 6 5 0

async与await的原理

  • async 、await实际上就是对 generator 封装的一个语法糖

多个异步嵌套

      function queryData() {
        return new Promise(function (resolve) {
          resolve(111)
        })
      }
      queryData()
        .then(res => {
          console.log('第一个异步res', res)
          return Promise.resolve(222)
        })
        .then(res => {
          console.log('第二个异步res', res)
        })
        .catch(err => {
          console.log('error', err)
        })
      // 如果有多个异步的话,需要使用多个then来处理异步之间可能存在的同步关系

es6 之 使用yield 的方式

      // 模拟一个请求
      function request() {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve({
              data: '我是data数据'
            })
          }, 1000)
        })
      }
      //用yield 获取request的值
      function* genGetData() {
        yield request()
      }
      const g = genGetData()
      const { value } = g.next()
      // console.log('g', g, 'value', value, 'done', done)
      // 间隔1s后打印 {data:"我是data数据"}
      value.then(res => {
        console.log('data', res)
      })
      // 输出结果:data {data: '我是data数据'}

es7 之 async 与 await的简写

      // 使用async 和 await的写法
      async function asyncGetData() {
        const result = await request()
        const result2 = await request()
        console.log('result', result, 'result2', result2)
      }
      asyncGetData()

事件机制

  • 事件分为两种事件:事件冒泡、事件捕获

  • 事件一个触发流程:

    • 当前目标阶段 - 事件捕获 - 事件冒泡
  • 事件冒泡

    • 当前目标阶段 - 逐层向上冒泡,会触发与当前目标阶段相同的事件,直至document
    • 阻止事件冒泡
      • e.stopPropagation()
      • return false
      • cancelBubble = true
      • 再vue里面 添加 .stop事件修饰符
  • 事件捕获

    • 从document逐层向下捕获事件,直到当前目标阶段为止
    • 阻住默认事件
      • event. preventDefault()
      • vue里面 添加 .prevent事件修饰符
  • 冒泡事件之事件委托

    • 就是原本 一个ul父容器包裹着 许多li子容器,想要对子容器添加事件,但是事件多,这时候就可以事件挂载再父容器之中,进行事件委托
    <ul id="ul">
    	<li>1</li>
      <li>2</li>
    	<li>3</li>
    </ul>
    	let ul = document.querySelector('#ul')
    	ul.addEventListener('click', (event) => {
    		console.log(event.target);
    	})
    
  • addEventListener 的事件捕获

    dom.addEventListener('click',function(){
       console.log("button被点击")
    },true)
    
  • 点击冒泡

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值