JavaScript 异步编程与请求取消全指南


JavaScript 异步编程与请求取消全指南

涵盖:同步/异步、Promise、async/await、AbortController、前后端协作


一、同步与异步

1. 同步(Synchronous)

  • 定义:代码按顺序执行,前一步完成才能执行下一步。

  • 特点:阻塞主线程,适合简单逻辑。

  • 示例

    javascript 复制代码
    console.log("步骤1");  
    console.log("步骤2"); // 必须等待步骤1完成

2. 异步(Asynchronous)

  • 定义:代码非阻塞执行,任务完成后通过回调、Promise 或事件通知结果。

  • 特点:高效但复杂度高,适合网络请求、I/O 操作。

  • 示例

    javascript 复制代码
    setTimeout(() => console.log("异步任务"), 1000);  
    console.log("继续执行"); // 立即执行

二、Promise 核心知识

1. 基本概念

  • 状态Pending(进行中)、Fulfilled(成功)、Rejected(失败)。

  • 创建与使用

    javascript 复制代码
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => resolve("成功"), 1000);
    });
    promise.then(result => console.log(result));  

2. 链式调用与静态方法

  • 链式调用

    javascript 复制代码
    fetch(url)
      .then(response => response.json())
      .catch(error => console.error(error));
  • 静态方法

    • Promise.all():所有成功返回结果数组。
    • Promise.race():返回第一个完成的结果。

三、async/await 进阶

1. 基本用法

  • async 函数:隐式返回 Promise。

  • await :等待 Promise 完成并提取结果。

    javascript 复制代码
    async function fetchData() {
      const data = await fetch(url);
      return data.json();
    }

2. 错误处理

  • try...catch :捕获异步错误。

    javascript 复制代码
    async function safeFetch() {
      try {
        const data = await fetch(url);
      } catch (error) {
        console.error("请求失败:", error);
      }
    }

3. 并发控制

  • 串行

    javascript 复制代码
    await task1();  
    await task2(); // 等待 task1 完成
  • 并行

    javascript 复制代码
    const [res1, res2] = await Promise.all([task1(), task2()]);

四、请求取消:AbortController

1. 核心功能

  • 中断异步操作 (如 fetch 请求)。
  • 核心对象
    • AbortController:生成中断信号。
    • AbortSignal:传递给异步任务。

2. 使用示例

javascript 复制代码
const controller = new AbortController();

// 发起请求并传递信号
fetch(url, { signal: controller.signal })
  .catch(error => {
    if (error.name === "AbortError") {
      console.log("请求已取消");
    }
  });

// 用户点击取消按钮
document.getElementById("cancel-btn").onclick = () => controller.abort();

3. 超时自动取消

javascript 复制代码
async function fetchWithTimeout(url, timeoutMs) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
  
  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(timeoutId); // 请求成功时清除定时器
    return response.json();
  } catch (error) {
    if (error.name === "AbortError") {
      throw new Error(`超时(${timeoutMs}ms)`);
    }
  }
}

五、后端处理请求取消(Java/Spring Boot)

1. 默认行为

  • 客户端断开后,服务器继续执行任务

  • 示例

    java 复制代码
    @GetMapping("/data")
    public String longTask() throws InterruptedException {
      Thread.sleep(5000); // 即使客户端断开仍会执行
      return "完成";
    }

2. 主动终止任务

  • 监听连接中断 (使用 DeferredResult):

    java 复制代码
    @GetMapping("/async")
    public DeferredResult<String> asyncTask() {
      DeferredResult<String> deferredResult = new DeferredResult<>();
      Future<?> future = executor.submit(() -> {
        try {
          Thread.sleep(5000);
          deferredResult.setResult("完成");
        } catch (InterruptedException e) {
          deferredResult.setErrorResult("已取消");
        }
      });
      // 客户端断开时取消任务
      deferredResult.onCompletion(() -> future.cancel(true));
      return deferredResult;
    }

3. 数据库查询超时

java 复制代码
@Query(value = "SELECT * FROM large_table", timeout = 5) // 5秒超时
List<Record> findLargeData();

六、关键问题解答

1. 客户端取消请求后,后端是否继续执行?

  • 默认继续执行,需后端主动监听连接中断事件并终止任务。

2. 为什么需要 async 函数?

  • 语法要求await 必须在 async 函数内使用。
  • 隐式返回 Promise:方便异步操作的值传递。

3. 如何避免回调地狱?

  • 使用 Promise 链式调用async/await

七、最佳实践

  1. 前端
    • 使用 AbortController 取消不再需要的请求。
    • 超时设置避免长时间等待。
  2. 后端
    • 监听客户端断开事件,终止耗时操作。
    • 数据库操作设置查询超时。
  3. 通用
    • 关键业务设计幂等性逻辑(如支付去重)。

总结:异步编程需兼顾效率与资源管理,合理使用取消机制可显著提升应用性能和用户体验。

相关推荐
故事不长丨40 分钟前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
源心锁1 小时前
👋 手搓 gzip 实现的文件分块压缩上传
前端·javascript
哈库纳玛塔塔1 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy2 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
Kagol2 小时前
JavaScript 中的 sort 排序问题
前端·javascript
天“码”行空2 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
cos3 小时前
Fork 主题如何更新?基于 Ink 构建主题更新 CLI 工具
前端·javascript·git
odoo中国3 小时前
Odoo 19 模块结构概述
开发语言·python·module·odoo·核心组件·py文件按
代码N年归来仍是新手村成员4 小时前
【Java转Go】即时通信系统代码分析(一)基础Server 构建
java·开发语言·golang
Z1Jxxx4 小时前
01序列01序列
开发语言·c++·算法