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 @   Frose  阅读(589)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示