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. 通用
    • 关键业务设计幂等性逻辑(如支付去重)。

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

相关推荐
rockmelodies7 分钟前
【PHP7内核剖析】-1.1 PHP概述
开发语言·php
又菜又爱玩呜呜呜~18 分钟前
go使用反射获取http.Request参数到结构体
开发语言·http·golang
摸鱼仙人~23 分钟前
一文详解 Python 密码哈希库 Passlib
开发语言·python·哈希算法
小伟童鞋36 分钟前
c++中导出函数调用约定为__stdcall类型函数并指定导出函数名称
开发语言·c++
百思可瑞教育36 分钟前
Vue中使用keep-alive实现页面前进刷新、后退缓存的完整方案
前端·javascript·vue.js·缓存·uni-app·北京百思可瑞教育
维C泡泡36 分钟前
C++初认、命名规则、输入输出、函数重载、引用+coust引用
开发语言·c++
a73601541 分钟前
二十二、包管理与发布 (Cargo 进阶)
开发语言·rust
郝学胜-神的一滴2 小时前
深入探索 C++ 元组:从基础到高级应用
开发语言·c++·stl·软件工程
I'm a winner2 小时前
第七章:AI进阶之------输入与输出函数(一)
开发语言·人工智能·python·深度学习·神经网络·microsoft·机器学习