写作时间:2025-08-20

💡 什么是javascript异步编程:
JavaScript 异步编程是指在 JavaScript 代码执行过程中,不按照代码的先后顺序同步执行所有操作,而是允许某些耗时操作(如网络请求、文件读写、定时器等)在后台执行,同时继续执行后续代码,待耗时操作完成后再通过特定机制处理其结果的编程模式。

🌌 特点:

  • 非阻塞:耗时操作不会阻塞后续代码的执行。
  • 结果回调:耗时操作完成后,通过特定方式(如回调函数、Promise 等)通知并处理结果。
  • 顺序可控:即使操作异步执行,也能通过机制保证代码按预期顺序执行(如链式调用、async/await)。

异步编程的实现方式

1. 回调函数(callback)

定义: 将一个函数作为参数传入另一个函数,当异步操作完成后,这个函数会被自动调用,以处理操作结果。

基本用法

// 模拟异步读取文件
function readFile(filename, callback) {
  // 模拟耗时操作(如真实的文件读取)
  setTimeout(() => {
    const content = `内容:${filename}`;
    // 操作完成后调用回调函数,传递结果
    callback(content); 
  }, 1000);
}

// 调用:读取完成后打印内容
readFile('note.txt', (result) => {
  console.log(result); // 1秒后输出:内容:note.txt
});
console.log('开始读取...'); // 立即执行,不阻塞

优点

  • 简单直接,是异步编程的基础
  • 适用于简单的单次异步操作

缺点

  • 回调地狱:多个异步操作需要按顺序执行时,会导致代码嵌套层级过深,可读性和可维护性差。javascript运行
// 回调地狱示例(嵌套层级过深)
step1((res1) => {
  step2(res1, (res2) => {
    step3(res2, (res3) => {
      // ... 更多嵌套
    });
  });
});

// 错误处理麻烦,需要在每个回调中单独处理

2. Promise

定义: ES6 引入的对象,用于封装异步操作的结果(成功 / 失败),通过链式调用解决回调地狱问题。

核心状态

  • pending:初始状态,操作未完成
  • fulfilled:操作成功,触发 then 方法
  • rejected:操作失败,触发 catch 方法
// 创建Promise对象(封装异步操作)
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve('操作成功的结果'); // 成功时调用resolve
    } else {
      reject('操作失败的原因'); // 失败时调用reject
    }
  }, 1000);
});

// 处理结果(链式调用)
promise
  .then(result => {
    console.log('第一步处理:', result);
    return '中间结果'; // 传递给下一个then
  })
  .then(data => {
    console.log('第二步处理:', data);
  })
  .catch(error => {
    console.log('错误处理:', error); // 捕获整个链中的错误
  })
  .finally(() => {
    console.log('无论成功失败都会执行');
  });

常用静态方法

  • Promise.all([p1, p2, p3]):等待所有 Promise 成功,返回结果数组;任何一个失败则立即失败
  • Promise.race([p1, p2]):返回第一个完成(成功或失败)的 Promise 结果
  • Promise.resolve(value):直接返回一个成功状态的 Promise
  • Promise.reject(error):直接返回一个失败状态的 Promise

优点

  • 解决回调地狱,通过链式调用使代码线性化
  • 集中处理错误(一个 catch 捕获整个链的错误)
  • 支持并行 / 竞争等复杂异步场景(通过静态方法)

缺点

  • 无法中途取消,一旦创建就会执行
  • 代码仍有一定冗余(then 调用链)

3. async/await

定义: ES2017 引入的语法糖,基于 Promise 实现,让异步代码的写法更接近同步代码,可读性更强。

核心规则

  • async:声明一个异步函数,该函数默认返回 Promise
  • await:只能在 async 函数中使用,用于等待 Promise 完成并获取结果(会暂停当前函数执行,直到 Promise 状态改变)
// 异步函数(返回Promise)
function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => resolve('数据内容'), 1000);
  });
}

// 使用async/await处理
async function handleData() {
  try {
    console.log('开始');
    const data = await fetchData(); // 等待异步操作完成
    console.log('获取到数据:', data); // 1秒后执行
    return '处理完成';
  } catch (error) {
    console.log('错误:', error); // 捕获错误
  }
}

// 调用异步函数(返回Promise)
handleData().then(result => {
  console.log(result); // 输出:处理完成
});

处理并行操作

async function loadAll() {
  // 同时发起多个请求(并行)
  const promise1 = fetchData('url1');
  const promise2 = fetchData('url2');
  
  // 等待所有完成
  const [res1, res2] = await Promise.all([promise1, promise2]);
  console.log(res1, res2);
}

优点

  • 代码结构清晰,像同步代码一样直观
  • 错误处理简单,可使用 try/catch 统一处理
  • 更易实现复杂的异步流程控制

缺点

  • 依赖 Promise,本质是 Promise 的语法糖
  • await 会阻塞当前 async 函数的执行(但不阻塞主线程)

宏任务与微任务

1.什么是宏任务和微任务

JavaScript 是单线程语言,为了避免耗时操作(如网络请求、定时器)阻塞主线程,设计了异步任务队列。根据任务的优先级和类型,异步任务被分为两类:

  • 宏任务:优先级较低的异步任务,通常是浏览器或 Node.js 环境发起的 “宏观” 操作(如定时器、I/O 操作)。
  • 微任务:优先级较高的异步任务,通常是 JavaScript 引擎内部发起的 “微观” 操作(如 Promise 的回调、队列操作)。

2.宏任务和微任务的具体区分

2-1. 宏任务(Macro Task)

常见类型包括:

  • setTimeoutsetInterval:定时器回调
  • setImmediate(Node.js 环境):立即执行的回调(类似 setTimeout 0,但优先级不同)
  • I/O 操作:如文件读写、网络请求(Ajax、Fetch)的回调
  • UI 渲染:浏览器对 DOM 的渲染操作
  • script 标签中的全局代码:整个脚本的执行本身属于第一个宏任务
2-2. 微任务(Micro Task)

常见类型包括:

  • Promise.then()Promise.catch()Promise.finally():Promise 的回调函数
  • async/await:本质是 Promise 的语法糖,await 后的代码会被包装为微任务
  • queueMicrotask():显式添加微任务的 API(ES6 新增)
  • process.nextTick()(Node.js 环境):优先级高于其他微任务的特殊微任务

3.执行机制

JavaScript 的事件循环遵循 “先执行同步代码,再处理异步任务,微任务优先于宏任务” 的规则,具体步骤如下:

  1. 执行同步代码:从全局执行栈开始,按顺序执行所有同步代码(同步代码属于第一个宏任务的一部分)。
  2. 清空微任务队列:同步代码执行完毕后,检查微任务队列。如果有微任务,按顺序全部执行完(包括执行微任务过程中新增的微任务)。
  3. 执行一个宏任务:微任务队列清空后,从宏任务队列中取第一个宏任务执行。
  4. 重复步骤 2 和 3:每次执行完一个宏任务后,立即清空微任务队列,再执行下一个宏任务,循环往复。

核心流程:同步代码 → 所有微任务 → 一个宏任务 → 所有微任务 → 下一个宏任务...

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐