JS时间循环宏任务微任务 讲解+面试题

什么是事件循环?

事实上我把事件循环理解成我们编写的JavaScript和浏览器或者Node之间的一个桥梁

浏览器的事件循环是一个我们编写的JavaScript代码和浏览器API调用(setTimeout/AJAX/监听事件等)的一个桥梁, 桥梁之间他们通过回调函数进行沟通。

Node的事件循环是一个我们编写的JavaScript代码和系统调用(file system、network等)之间的一个桥梁, 桥梁 之间他们通过回调函数进行沟通的

JS代码执行流程

 

  • 定义变量name;
  • 执行log函数,函数会被放入到调用栈中执 行;
  • 调用bar()函数,被压入到调用栈中,但是执 行未结束;
  • bar因为调用了sum,sum函数被压入到调 用栈中,获取到结果后出栈;
  • bar获取到结果后出栈,获取到结果result;
  • 将log函数压入到调用栈,log被执行,并且 出栈

浏览器中事件循环

如果执行JS中存在异步操作,例如setTimeout(),则会被放入调用栈中,执行会结束,不会阻塞后面代码运行

其实内部调用 web API,在合适的时机将函数加入到事件队列中

事件队列中的函数会被放入调用栈,然后被执行。

宏任务、微任务

事件循环中事实上有两个队列

  • 宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
  • 微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()等

那么事件循环对于两个队列的优先级是怎么样的呢?

  1. main script中的代码优先执行(编写的顶层script代码);
  2. 在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行
    • 也就是宏任务执行之前,必须保证微任务队列是空的; 
    • 如果不为空,那么久优先执行微任务队列中的任务(回调)

 

面试题

1

setTimeout(function () {
  console.log("set1");
  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("pr1");
  resolve();
}).then(function () {
  console.log("then1");
});

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

console.log(2);

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

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

// pr1
// 2
// then1
// queuemicrotask1
// then3
// set1
// then2
// then4
// set2

2

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('setTimeout')
}, 0)
 
async1();
 
new Promise (function (resolve) {
  console.log('promise1')
  resolve();
}).then (function () {
  console.log('promise2')
})

console.log('script end')


// script start
// async1 start
// async2
// promise1
// script end
// aysnc1 end
// promise2
// setToueout

注意:

Promise中的为同步代码块,then后为异步 微任务

Async  函数中:await前的可以看做Promise外部的diamante  

         await相当于在执行Promise中的为同步代码块  

         await后的相当于在执行then的回调 微任务

 

posted @ 2021-11-13 15:10  Frose  阅读(653)  评论(0)    收藏  举报