js 的宏任务和微任务

news2024/12/23 17:32:40

宏任务 (macro-task) 与微任务 (micro-task)

在 JavaScript 中,宏任务(macro-task)和微任务(micro-task)是任务队列(task queue)中两个不同的任务类型,它们是 JavaScript 异步编程机制的重要组成部分。

事件循环(Event Loop)是 JavaScript 中处理异步操作的机制,它确保代码按预期顺序执行,同时保持 js 单线程的特性。事件循环不断检查任务队列,按照一定规则处理同步代码、宏任务和微任务,并决定何时执行它们。

宏任务是事件循环中的主要任务队列;宏任务会在每轮事件循环中依次执行,执行完一个宏任务后,事件循环会检查是否有需要执行的微任务队列。常见的宏任务:主代码块(script)、setTimeout、setInterval、I/O 操作、UI rendering。

微任务优先级更高,它会在当前宏任务执行完后立即执行,并在下一个宏任务开始前完成。微任务可以在不等到下一轮事件循环的情况下进行。常见的微任务:Promise.then / Promise.catch / Promise.finally、MutationObserver、queueMicrotask。

注意:当 new Promise 时,此时视为宏任务的状态。当 resolvereject 时,把它们加入到微任务队列中,例如练习 2。
总结:事件循环每次迭代会执行一个宏任务的所有脚本,然后处理所有微任务。

执行顺序:
① JavaScript 先执行当前宏任务中的同步代码;
② 如果执行过程中遇到微任务,它会被加入微任务队列,但不会立即执行;
③ 当前宏任务中的所有同步代码执行完毕后,会执行微任务队列中的所有微任务,直到队列为空;
④ 微任务队列清空后,事件循环将继续执行下一个宏任务。

console.log('宏任务开始');  // 同步代码,立即执行

setTimeout(() => {
  console.log('宏任务:setTimeout');  // 宏任务
}, 0);

Promise.resolve().then(() => {
  console.log('微任务:Promise 1');  // 微任务
}).then(() => {
  console.log('微任务:Promise 2');  // 微任务
});

console.log('宏任务结束');  // 同步代码,立即执行

按照上面的内容,分析执行步骤:

  1. 宏任务:执行整体代码(相当于 <script> 中的代码):
    输出:宏任务开始
    遇到 setTimeout,加入宏任务队列,当前宏任务队列 [setTimeout]
    遇到 Promise.resolve().then(),加入微任务,当前微任务队列 [promise1]
    输出:宏任务结束

  2. 微任务:执行微任务队列 [promise1]
    输出:微任务:promise1
    遇到 then,加入微任务队列,当前微任务队列 [then()]
    【微任务队列中不为空】执行微任务队列 [then()],输出:微任务:promise2

  3. 执行渲染操作,更新界面(敲黑板划重点)。

  4. 宏任务:执行 setTimeout
    输出:宏任务:setTimeout

练习

在线运行 JavaScript ,在这个网站上输出下方练习的结果。
要就来45道Promise面试题一次爽到底 这里有更多的关于 Promise 的面试题。

练习 1

const promise1 = new Promise((resolve, reject) => {
  console.log('promise1')
})
console.log('1', promise1);

练习 2

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve('success')
  console.log(2);
});
promise.then(() => {
  console.log(3);
});
console.log(4);

练习 3

const promise = new Promise((resolve, reject) => {
  console.log(1);
  console.log(2); 
});
promise.then(() => {  
  console.log(3);
});
console.log(4);

练习 4

const fn = () =>
  new Promise((resolve, reject) => {
    console.log(1);
    resolve("success");
  });
console.log("start"); 
fn().then(res => {
  console.log(res);
});

练习 5

console.log("script start");

setTimeout(function () {
  console.log("setTimeout");
}, 0);   

Promise.resolve()
  .then(function () {
    console.log("promise1");
  })
  .then(function () {
    console.log("promise2");
  });
console.log("script end");

练习 6:

const promise = new Promise((resolve, reject) => {
  console.log(1);
  setTimeout(() => {
    console.log("timerStart");
    resolve("success");
    console.log("timerEnd");
  }, 0);
  console.log(2);
});
promise.then((res) => {
  console.log(res);
});
console.log(4);

练习 7

setTimeout(() => {
  console.log('timer1');
  Promise.resolve().then(() => {
    console.log('promise')
  })
}, 0)
setTimeout(() => {
  console.log('timer2')
}, 0)
console.log('start')

练习 8

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)
运行结果

练习 1:

promise1
1 Promise {<pending>}

练习 2

1 
2 
4 
3

练习 3:
这里 promise.then() 不会执行

1 
2 
4

练习 4
这里 fn 函数包裹着 new Promise,因此只有当 fn 被调用时,里面的 new Promise 才会被执行。

start
1
success

练习 5

script start
script end
promise1
promise2
setTimeout

练习 6:
① 从上到下同步完后,微任务队列并没有任务,而宏任务队列有一个 setTimeout,因此下一个执行宏任务队列里的任务;
② 当完成执行完 setTimeout,微任务队列里存在 Promise.then()
③ 执行 Promise.then() 的内容。

1
2
4
timerStart
timerEnd
success

练习 7
① 同步整个代码后,宏任务队列里面含有第一个 setTimeout 和第二个 setTimeout,而微任务队列里为空;
② 取出第一个 setTimeout,然后执行代码。执行完成后,微任务队列新增了一个 Promise.then
③ 执行 Promise.then
④ 执行第二个 setTimeout

start
timer1
promise
timer2

练习 8
考察 Promise 的三种状态。

'promise1' Promise{<pending>}
'promise2' Promise{<pending>}
test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102
'promise1' Promise{<resolved>: "success"}
'promise2' Promise{<rejected>: Error: error!!!}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2224470.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DBeaver查看已保存连接的密码

打开Dbeaver窗口菜单-首选项-工作空间&#xff0c;找到工作空间路径 在文件管理器中打开工作空间路径\General.dbeaver&#xff0c;找到credentials-config.json。 在Linux下&#xff0c;使用如下命令对credentials-config.json文件进行解密 openssl aes-128-cbc -d -K babb4…

13 实战:使用Python和Pygame实现视频运动估计播放器

首先看运行效果: 在多媒体处理领域,视频的运动估计是一个重要的课题。在本文中,我们将详细介绍如何使用Python结合Pygame、OpenCV等库,实现一个支持运动估计的视频播放器。本项目旨在展示如何在Python中处理视频帧,实现块匹配算法进行运动估计,并将结果以可视化的方式呈现…

kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?

大家好&#xff0c;我是锋哥。今天分享关于【kafka 分布式&#xff08;不是单机&#xff09;的情况下&#xff0c;如何保证消息的顺序消费?】面试题&#xff1f;希望对大家有帮助&#xff1b; kafka 分布式&#xff08;不是单机&#xff09;的情况下&#xff0c;如何保证消息的…

TypeScript基础简介

TypeScript是Javascript的一个超集。 TypeScript在原有的基础之上又添加了编译器类型检查的功能&#xff0c;意味着如果使用ts进行开发&#xff0c;会对变量的类型进行较为严格的验证&#xff0c;防止程序员写出可能出错的代码&#xff0c;规范变成习惯&#xff0c;适合大项目开…

2024年MathorCup妈杯大数据竞赛选题人数发布

经过24个小时&#xff0c;各个平台的相关选题投票、相关文章阅读量等各项数据进行统计&#xff0c;利用之前的评估办法&#xff08;详见注释&#xff09;。在开赛后24小时&#xff0c;我们基本确定各个赛题选题人数&#xff0c;以帮助大家更好地分析赛题局势。 题目人数A46B72 …

【Vulnhub靶场】DC-4

DC-4靶场下载地址https://www.five86.com/downloads/DC-4.zip 本机IP&#xff1a;192.168.118.128 靶机IP&#xff1a;192.168.118.0/24 信息收集 扫描主机存活&#xff0c;扫描端口&#xff0c;扫描服务 第一步扫描出主机ip为192.168.118.141 nmap -sP 192.168.118.0/24 nm…

Java后端面试题:Java基础篇

目录 Java基础 1.请你说说Java中基本数据类型的bit长度&#xff1f; 2.switch支持哪些数据类型&#xff1f;支持long么&#xff1f; 3.讲一下常见编码方式&#xff1f; 4.char能不能存储中文&#xff1f; 5.为什么数组索引从0开始呢&#xff1f;假如从1开始不行吗&#xf…

Java篇图书管理系统

目录 前言 一. 图书管理系统的核心 二. 图书管理系统基本框架 2.1 book包 2.1.1 Book&#xff08;书籍类&#xff09; 2.1.2 Booklist (书架类&#xff09; 2.2 user包 2.2.1 User类 2.2.2 Administrator(管理员类) 2.2.3 Visitor&#xff08;用户类&#xff09; 2.…

数据结构 - 散列表,初探

今天我们继续学习新的数据结构-散列表。 01定义 我们先来了解一些常见概念名词解释。 散列&#xff1a;散列表的实现叫做散列&#xff0c;是一种实现以常数级时间复杂度执行查找、插入和删除的技术&#xff1b; 散列值&#xff1a;通过散列函数对输入值&#xff08;key&…

【c++篇】:从基础到实践--c++内存管理技巧与模版编程基础

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.c/c内存分布二.c/c的动态内存管理方式2.1.c语言的动态内存管…

JavaEE初阶---多线程(五)---定时器/线程池介绍

文章目录 1.定时器的介绍2.线程池2.1为什么需要使用线程池2.2如何进行线程池的创建2.3普通的构造方法的局限性2.4该种对象创建的方法的特点2.5线程池的模拟实现的逻辑 3.ThreadPoolExecutor类的介绍3.1构造方法3.2四种拒绝的策略 1.定时器的介绍 下面的这个就是我们的这个定时…

基于JSP的高校食堂食材选购管理系统【附源码】

基于JSP的高校食堂食材选购管理系统 效果如下&#xff1a; 系统首页界面 用户登录页面 食材信息页面 论坛交流界面 管理员登录界面 管理员功能主界面 食材信息管理界面 订单配送管理界面 用户功能主界面 商家功能主界面 司机功能主界面 研究背景 近年来互联网技术的发展使得…

【C++篇】手撕string类:从初级到高级入门

1.为什么手撕string类 在面试或者一些学习场景中&#xff0c;手撕 string 类不仅仅是对字符串操作的考察&#xff0c;更多的是考察程序员对 C 内存管理的理解。例如&#xff0c;深拷贝与浅拷贝的实现&#xff0c;如何正确重载赋值运算符&#xff0c;如何避免内存泄漏&#xff…

线上环境的 JAVA 程序占用太多 CPU 资源,定位原因

线上环境的 JAVA 程序占用太多 CPU 资源&#xff0c;定位原因 top 命令执行显示一下结果 我们可以看到有一个 PID 是 4054 的应用程占用了超过一半的 CPU 资源&#xff0c;这是十分糟糕的事情&#xff0c;这个时候我们首先定位一下他是哪个线程在这里搞事情&#xff0c;这个时…

【JavaSE】认识String类,了解,进阶到熟练掌握

#1024程序员节 | 征文# 下面就让博主带领大家一起解决心中关于String类的疑问吧~~~ 1.字符串构造&#xff1a; 第一种和第二种&#xff08;有一定的区别&#xff0c;在常量池上&#xff09; public static void main(String[] args) { // 使用常量串构造 String s1 "h…

【机器学习】——numpy教程

文章目录 1.numpy简介2.初始化numpy3.ndarry的使用3.1numpy的属性3.2numpy的形状3.3ndarray的类型 4numpy生成数组的方法4.1生成0和1数组4.2从现有的数组生成4.3生成固定范围的数组4.4生成随机数组 5.数组的索引、切片6.数组的形状修改7.数组的类型修改8.数组的去重9.ndarray的…

【Visual Studio】下载安装 Visual Studio Community 并配置 C++ 桌面开发环境的图文教程

引言 Visual Studio 是一个面向 .NET 和 C 开发人员的综合性 Windows 版 IDE&#xff0c;可用于构建 Web、云、桌面、移动应用、服务和游戏。 安装步骤 访问 Visual Studio 的官方下载页面&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads/运行已下载的 V…

java疫苗发布和接种预约系统源码(springboot)

项目简介 疫苗发布和接种预约系统实现了以下功能&#xff1a; 疫苗发布和接种预约系统的主要使用者分为&#xff1a; 管理员对公告信息&#xff0c;医院信息&#xff0c;疫苗信息&#xff0c;医生信息&#xff0c;用户信息&#xff0c;论坛帖子信息以及预约接种信息等信息进行…

ThinkPad T480拆机屏幕改装:便携式显示器DIY指南

ThinkPad T480拆机屏幕改装&#xff1a;便携式显示器DIY指南 本文记录了将旧笔记本电脑 T480 拆机屏幕改装为便携式显示器的全过程。作者在决定升级设备后&#xff0c;选择通过 DIY 方式利用原有的屏幕资源。文章详细介绍了屏幕驱动板的安装、螺丝孔的剪裁、排线连接及固定的步…

系统性能优化——绑核

简要 绑核正如其名&#xff0c;将线程/进程绑定在一个或多个CPU核心。该技术可以使进程或线程在特定的处理器上运行&#xff0c;而不会被操作系统调度到其他处理器上。这里有两层含义。 如果线程被绑定在指定核心上&#xff0c;则只会在该核心上运行&#xff0c;即使其他核心…