浏览器环境中的EventLoop

152 阅读2分钟
Event Loop分为浏览器需要区分浏览器环境和Node环境。我目前关心点在于浏览器环境。


所谓事件环即:主线程循环不停的从任务队列中读取任务。


基础概念:

   1. javascript是主线程(用于用户交互和操作DOM)为单线程,可以有多个受控于主线程的子线程用于计算等(不能操作DOM)。

  2. 主线程中的任务是同步任务,同步任务位于执行栈中,按照顺序执行,执行栈清空后才去任务队列读取任务。

  3. 异步任务主要用于解决I/O设备或者计算速度较慢的问题。属于子线程。

  4. 任务队列中全部为异步任务(回调函数),微任务,宏任务。

    微任务: promise的then()方法

    宏任务:

  • setTimeout,setInterval
  • setImmediate(只兼容IE,默认低于setTimeout(0))
  • MutationObserver(性能有问题被弃用)
  • MessageChannel(高版本浏览器)

执行顺序(同步任务执行完后)

1. 只有异步任务时。

    异步任务来源主要有I/O设备,用户交互和Network事件,如键盘键入,鼠标单击和页面滚        动等触发事件。

    遇到异步任务时异步任务先被挂起,等回调函数拿到返回结果后才进入任务队列等待被主线      程调用。

    等到执行栈中的同步任务执行完成后,主线程才到任务队列中读取异步任务。任务队列中的      任务执行顺序依照“先进先出”。主线程依次从任务队列中读取任务。

2. 只有定时任务时。

    根据时间排序,当时间到达后,把对应回调放到队列。

    

setTimeout(() => {
  console.log(1);
  setTimeout(() => {
    console.log(4);
  }, 1000);
}, 1000);
setTimeout(() => {
  console.log(2);
}, 2000);
setTimeout(() => {
  console.log(3);
}, 3000);

执行顺序为1,2,4,3


3. 当任务队列中同时有微任务和宏任务时。(微任务先于宏任务)

  •   执行微任务,先把微任务清空
  •   执行一个宏任务
  •   再去执行微任务,清空
  •   执行一个宏任务(依次不停循环)

    setTimeout(() => {
      console.log('setTimeout1')
      Promise.resolve().then(data => {
        console.log('微任务1')
      })
    }, 0);
    Promise.resolve().then(data=>{
      console.log('微任务2')
      setTimeout(() => {
        console.log('setTimeout2')
      }, 0);
    });

       执行结果是: 微任务2,setTimeout1,微任务1,setTimeout2.