Event loop分享

122 阅读2分钟

一、任务类型

  • macro-task: script(整体代码)、setTimeoutsetInterval、setImmediate、I/O、UI rendering
  • micro-task: process.nextTick、Promise(这里指浏览器实现的原生 Promise)、Object.observe、MutationObserver、queueMicrotask

ajax请求不属于宏任务,js线程遇到ajax请求,会将请求交给对应的http线程处理,一旦请求返回结果,就会将对应的回调放入宏任务队列,等请求完成执行。

二、几个微任务宏任务小例子

(1)

setTimeout(function () {
  console.log("setTimeout1");

  new Promise(function (resolve) {
      resolve();
  }).then(function () {
      new Promise(function (resolve) {
          resolve();
      }).then(function () {
          console.log("then4");
      });
      console.log("then2");
  });
});

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("then1");
});

setTimeout(function () {
  console.log("setTimeout2");
});

console.log(2);

queueMicrotask(() => {
  console.log("queueMicrotask1")
});

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

(2)

async function async1() {
  console.log('async1 start')
  // await异步函数的返回结果 resolve的结果会作为整个异步函数的promise的resolve结果->同步代码
  // await后面的执行代码 就会变成.then后面的执行函数->微任务
  // 也就是说  console.log('async1 end') 这一段是相当于then方法内的 会被加入微任务中
  await async2();
  console.log('async1 end')
}

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

console.log('script start')

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

async1();

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

console.log('script end')

(3) 为什么直接返回直接返回Promise.resolve(4) 微任务推迟两次呢?NewPromiseResolveThenableJob

Promise.resolve().then(() => {
  console.log(0);
  //1.直接返回4 微任务不会做任何延迟 
  // return 4
  //2.直接返回Promise.resolve(4) 微任务推迟两次
  // return Promise.resolve(4);
  //3.返回thenable对象
  return {
    then: ((resolve, reject) => {
      resolve(4);
    })
  }
}).then((res) => {
  console.log(res)
})

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

(4)nodejs 下的Event loop,微任务执行时nextTick优先执行

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

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

console.log('script start')

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

setTimeout(function () {
  console.log('setTimeout2')
}, 300)

setImmediate(() => console.log('setImmediate'));

process.nextTick(() => console.log('nextTick1'));

async1();

process.nextTick(() => console.log('nextTick2'));

new Promise(function (resolve) {
  console.log('promise1')
  resolve();
  console.log('promise2')
}).then(function () {
  console.log('promise3')
})

console.log('script end')

三、微任务 宏任务执行顺序

image.png 我们梳理一下事件循环的执行机制:
循环首先从宏任务开始,遇到script,生成执行上下文,开始进入执行栈,可执行代码入栈,依次执行代码,调用完成出栈。
执行过程中遇到上边提到的调度者,会同步执行调度者,由调度者将其负责的任务(回调函数)放到对应的任务队列中,直到主执行栈清空,然后开始执行微任务的任务队列。微任务也清空后,再次从宏任务开始,一直循环这一过程。

四、工作中遇到的一个应用场景 一个页面的多个组件,同时发送n个请求,请求顺序不确定,如何控制请求的发送顺序?