浅析Event Loop

139 阅读3分钟

前言

众所周知,JavaScript是一门单线程脚本语言,即同一时间只能做一件事。由于网络请求、用户交互、UI渲染等操作会阻塞主线程,所以就诞生了事件循环(Event Loop)的解决方案。

js单线程的原因

当多个操作DOM的线程任务同时进行时,浏览器无法判断其优先级。

异步执行机制

  1. 在主线程的执行栈中执行所有的同步任务
  2. 异步任务执行完毕后,会在任务队列中分发一个事件
  3. 当执行栈中所有的同步任务执行完毕后,检查任务队列中有没有需要执行的异步任务事件,将事件取出放到主线程的执行栈中执行。
  4. 重复步骤3

异步任务中的宏任务与微任务

宏任务:srcipt整体代码、setTimeout定时器、setInterval、UI渲染、I/O操作等 微任务:promise.then()、MutaionObserver()、process.nextTick()

事件循环

在js中事件循环是指在浏览器或者node.js运行时环境中负责管理执行顺序的机制。 在了解了异步执行机制以后,串联起宏任务与微任务,帮助我们更好的理解事件循环。在事件循环中,每一次循环可以理解为一个task,每一个task过程为:

  1. 执行先进入执行栈的宏任务(通常指的是srcipt整体代码)
  2. 检查是否存在微任务,如果存在则执行微任务,直至微任务队列清空
  3. 更新render渲染函数(每次事件循环的执行都可能影响页面重新渲染)
  4. 重复以上步骤(开始执行新的宏任务)

大致顺序为宏→微→宏

练习

(这里引用其他博主的练习题,自己能学会能理解就行)

console.log("1");

//setTimeout1
setTimeout(function () {
  console.log("2");
  new Promise(function (resolve) {
    console.log("3");
    resolve();
  }).then(function () {
    console.log("4");
  });
  //setTimeout2
  setTimeout(function () {
    console.log("5");
    new Promise(function (resolve) {
      console.log("6");
      resolve();
    }).then(function () {
      console.log("7");
    });
  });
  console.log("14");
});

new Promise(function (resolve) {
  console.log("8");
  resolve();
}).then(function () {
  console.log("9");
});

//setTimeout3
setTimeout(function () {
  console.log("10");
  new Promise(function (resolve) {
    console.log("11");
    resolve();
  }).then(function () {
    console.log("12");
  });
});

console.log("13");

解析:首先执行同步代码,此时打印1 8 13,promise.then()为微任务,执行栈中执行同步任务后,执行微任务此时打印9。此时所有微任务执行完毕,开始下一轮宏任务,目前宏任务队列中为setTimeout1和setTimeout3,首先执行setTimeout1,先打印2 3 14,此时又遇到promise.then(),即后执行4,执行setTimeout1时发现还存在宏任务,添加到宏任务队列中(setTimeout3之后),开始下一轮宏任务,目前宏任务队列中为setTimeout3和setTimeout2,区分好setTimeout3和setTimeout2的顺序后,后续打印顺序就好理解了,这里就不一一叙述了。总体打印顺序为1 8 13 9 2 3 14 4 10 11 12 5 6 7。

总结

之前对这些前端中常用的知识点理解的很浅,接下来边加深理解边更新一些相关知识。如有错误请各位多批评指正。