当前位置: 首页 > article >正文

JavaScript 中的异步任务、同步任务、宏任务与微任务

JavaScript 中的异步任务、同步任务、宏任务与微任务

在 JavaScript 的世界里,理解异步任务、同步任务、宏任务和微任务是非常重要的,它们共同构成了 JavaScript 独特的执行机制。

一、同步任务与异步任务

1. 同步任务

  • 定义:同步任务是在代码执行过程中,按照顺序依次执行的任务。每个同步任务必须等待前一个任务完成后才能开始执行。
  • 特点
    • 阻塞代码执行,直到任务完成。
    • 按照代码书写的顺序依次执行。
  • 示例
    console.log('同步任务 1');
    console.log('同步任务 2');
    
    在这个例子中,首先会输出“同步任务 1”,然后输出“同步任务 2”。这两个任务是按照顺序依次执行的,前一个任务完成后,后一个任务才会开始执行。

2. 异步任务

  • 定义:异步任务是在代码执行过程中,不会立即执行,而是在特定的时间或条件满足后才会执行的任务。异步任务不会阻塞代码的执行,允许其他任务在等待异步任务完成的过程中继续执行。
  • 特点
    • 不会阻塞代码执行,可以在后台执行。
    • 通常需要回调函数来处理结果。
  • 示例
    console.log('同步任务 1');
    setTimeout(() => {
        console.log('异步任务');
    }, 1000);
    console.log('同步任务 2');
    
    在这个例子中,首先会输出“同步任务 1”,然后输出“同步任务 2”。接着,由于setTimeout是一个异步任务,它会在 1000 毫秒后执行回调函数,输出“异步任务”。在等待异步任务执行的过程中,其他同步任务可以继续执行。

二、宏任务与微任务

1. 宏任务

  • 定义:宏任务是由浏览器或 Node.js 等环境提供的任务,通常包括setTimeoutsetIntervalAjax 请求DOM 事件等。宏任务会在主线程上依次执行,每个宏任务执行完毕后,会检查微任务队列是否为空,如果不为空,则执行微任务队列中的所有任务。
  • 特点
    • 执行时间相对较长。
    • 可能会导致页面的重新渲染。
  • 示例
    console.log('同步任务 1');
    setTimeout(() => {
        console.log('宏任务 1');
    }, 0);
    console.log('同步任务 2');
    
    在这个例子中,setTimeout中的回调函数是一个宏任务,会在同步任务执行完毕后被放入任务队列等待执行。即使设置的时间为 0,也不会立即执行,而是在同步任务执行完毕后,按照任务队列的顺序执行。

2. 微任务

  • 定义:微任务是在当前宏任务执行过程中产生的,并且会在当前宏任务执行完毕后立即执行。常见的微任务包括Promise.then()Promise.catch()Promise.finally()MutationObserver等。
  • 特点
    • 执行时间相对较短。
    • 优先级高于宏任务。
  • 示例
    console.log('同步任务 1');
    Promise.resolve().then(() => {
        console.log('微任务 1');
    });
    console.log('同步任务 2');
    
    在这个例子中,Promise.resolve().then()中的回调函数是一个微任务,会在同步任务执行完毕后,且在宏任务执行之前被执行。

三、事件循环

JavaScript 是单线程语言,通过事件循环来管理同步任务和异步任务的执行。事件循环的工作原理如下:

  1. 首先执行同步任务,将同步任务依次放入主线程执行。
  2. 当遇到异步任务时,将异步任务放入任务队列中等待执行。异步任务分为宏任务和微任务,分别放入不同的任务队列。
  3. 当主线程中的同步任务执行完毕后,会先检查微任务队列是否为空。如果微任务队列不为空,则执行微任务队列中的所有任务,这个过程会持续进行,直到微任务队列为空。
  4. 微任务队列处理完后,才会从宏任务队列中取出一个宏任务并执行,宏任务执行产生微任务会执行微任务队列的任务。
  5. 重复步骤 3 和 4,直到任务队列中的所有任务都被执行完毕。

例如:

console.log('同步任务 1');
setTimeout(() => {
    console.log('宏任务 1');
}, 0);
Promise.resolve().then(() => {
    console.log('微任务 1');
});
console.log('同步任务 2');

在这个例子中,首先执行“同步任务 1”和“同步任务 2”。然后,由于setTimeout是宏任务,它会被放入宏任务队列中等待执行。同时,Promise.resolve().then()是微任务,会被放入微任务队列中。当同步任务执行完毕后,会先执行微任务队列中的“微任务 1”,然后才会从宏任务队列中取出“宏任务 1”执行。

面试题:

console.log('同步任务 start');

setTimeout(() => {
    console.log('宏任务 1');
    Promise.resolve().then(() => {
        console.log('微任务 within 宏任务 1');
    });
}, 0);

Promise.resolve().then(() => {
    console.log('微任务 1');
    setTimeout(() => {
        console.log('宏任务 within 微任务 1');
    }, 0);
});

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

console.log('同步任务 end');

输出结果:

> "同步任务 start"
> "同步任务 end"
> "微任务 1"
> "宏任务 1"
> "微任务 within 宏任务 1"
> "宏任务 2"
> "宏任务 within 微任务 1"

以下是对上述代码执行流程的解释:

  1. 首先,执行同步任务。
    • 输出同步任务 start
    • 接着遇到第二个同步任务,输出同步任务 end
  2. 同步任务执行完毕后,开始检查微任务队列。
    • 此时微任务队列为空,所以继续从宏任务队列中取出任务执行。
  3. 从宏任务队列中取出第一个由setTimeout注册的宏任务执行。
    • 输出宏任务 1
    • 在这个宏任务中,又有一个Promise.resolve().then(),它会注册一个微任务,即console.log('微任务 within 宏任务 1');被放入微任务队列。
  4. 接着,回到宏任务队列继续检查是否还有未执行的宏任务。
    • 由于还有两个由setTimeout注册的宏任务未执行,但是根据事件循环机制,此时要先检查微任务队列。
  5. 微任务队列中有一个任务,即console.log('微任务 within 宏任务 1');,执行这个微任务,输出微任务 within 宏任务 1
  6. 微任务队列处理完毕后,再次从宏任务队列中取出下一个任务执行。
    • 输出宏任务 2
  7. 此时宏任务队列中还有一个任务,是在微任务 1中注册的setTimeout回调,即console.log('宏任务 within 微任务 1');
  8. 执行这个宏任务,输出宏任务 within 微任务 1

http://www.kler.cn/a/305018.html

相关文章:

  • 蓝队知识浅谈(上)
  • UDP协议和TCP协议之间有什么具体区别?
  • 从0开始学习Linux——文件管理
  • 三正科技笔试题
  • flink sql + kafka + mysql 如何构建实时数仓
  • 多叉树笔记
  • Vue3 Day1Day2-Vue3优势ref、reactive函数
  • 基于STM32设计的智能家庭防盗系统(华为云IOT)(224)
  • 速盾:你知道高防 IP 和高防 CDN 的区别吗?
  • 846. 树的重心
  • git-fork操作指南
  • Qt_信号与槽
  • 【洛谷】P9752 [CSP-S 2023] 密码锁
  • C++:opencv生成结构元素用于膨胀腐蚀等cv::getStructuringElement
  • 中级练习[6]:Hive SQL订单配送与用户社交行为分析
  • Windows 环境下安装、使用、nodeJs 连接 TiDB 数据库
  • 使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用
  • 外观模式详解:如何为复杂系统构建简洁的接口
  • UE4_后期处理六—夜视仪、扫描线
  • 瑞芯微RK3568鸿蒙开发板OpenHarmony系统修改cfg文件权限方法
  • 如何提升RAG检索的准确率及答案的完整性?
  • Qt与Udp
  • git update-ref
  • 网络安全 DVWA通关指南 DVWA SQL Injection (Blind SQL盲注)
  • 【iOS】单例模式
  • 使用 PyTorch 构建 MNIST 手写数字识别模型