Skip to content

JavaScript 异步解决方案全面解析

回调函数(Callback)

回调函数是 JavaScript 中最原始、最基础的异步处理方式。将一个函数作为参数传递给另一个函数,在异步操作完成后调用该函数。

javascript
function fetchData(url, callback) {
  ss
  const xhr = new XMLHttpRequest()
  xhr.open('GET', url)
  xhr.onload = function () {
    if (xhr.status === 200) {
      callback(null, xhr.responseText)
    } else {
      callback(new Error('Request failed'))
    }
  }
  xhr.send()
}

fetchData('/api/data', function (err, data) {
  if (err) {
    console.error(err)
    return
  }
  console.log(data)
})

优点:

  • 简单直观,容易理解
  • 兼容性极好,所有浏览器和 Node.js 环境都支持
  • 无需额外依赖,是 JavaScript 语言原生支持的方式
  • 适合简单的、单次的异步操作

缺点:

  • 回调地狱(Callback Hell):多层嵌套导致代码可读性极差,形成"金字塔"结构
  • 错误处理困难:无法使用 try/catch,每个回调都需要单独处理错误
  • 控制流混乱:难以实现并行、串行、竞速等复杂控制流
  • 耦合度高:回调函数与调用者紧密耦合,难以复用
  • 缺乏返回值:回调函数的返回值无法被外部获取

适用场景:

  • 简单的、单次异步操作(如事件监听、setTimeout)
  • Node.js 早期 API(fs.readFile 等)
  • 需要极致兼容性的旧项目
  • 作为其他异步方案的基础构建块

事件监听(Event Listeners)

利用 DOM 的事件机制或 Node.js 的 EventEmitter 来处理异步操作的结果。

javascript
// DOM 事件监听
const button = document.getElementById('myButton')
button.addEventListener('click', function (event) {
  console.log('Button clicked!', event)
})

// Node.js EventEmitter
const EventEmitter = require('events')
const emitter = new EventEmitter()

emitter.on('data', function (data) {
  console.log('Received data:', data)
})

emitter.on('error', function (err) {
  console.error('Error:', err)
})

// 触发事件
emitter.emit('data', { name: 'test' })

优点:

  • 解耦性好,发布者和订阅者互不依赖
  • 支持多个监听器,一个事件可以被多个函数响应
  • 可以随时添加或移除监听器,灵活性高
  • DOM 事件模型是前端开发的基础,使用自然

缺点:

  • 事件流程难以追踪,调试困难
  • 多个监听器的执行顺序不可控
  • 可能产生内存泄漏(忘记移除监听器)
  • 缺乏结构化的错误处理机制
  • 不适合需要返回值的场景
  • 一次性事件需要手动移除监听器(或使用 once)

适用场景:

  • DOM 交互(点击、输入、滚动等用户事件)
  • Node.js 中的 Stream 处理
  • 组件间通信(如 Vue 的 EventBus)
  • 需要一对多通知的场景

发布订阅模式(Pub/Sub Pattern)

发布订阅模式是事件监听的进阶版本,通过一个中心化的消息代理(Event Bus / Message Broker)来管理事件的发布和订阅。

javascript
class EventBus {
  constructor() {
    this.events = {}
  }

  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = []
    }
    this.events[event].push(callback)
    return () => this.off(event, callback)
  }

  off(event, callback) {
    if (!this.events[event]) return
    this.events[event] = this.events[event].filter(cb => cb !== callback)
  }

  emit(event, ...args) {
    if (!this.events[event]) return
    this.events[event].forEach(callback => callback(...args))
  }

  once(event, callback) {
    const wrapper = (...args) => {
      callback(...args)
      this.off(event, wrapper)
    }
    this.on(event, wrapper)
  }
}

const bus = new EventBus()
const unsubscribe = bus.on('user:login', user => {
  console.log(`Welcome, ${user.name}!`)
})

bus.emit('user:login', { name: 'Alice' })
unsubscribe() // 取消订阅

优点:

  • 完全解耦,发布者和订阅者互不知道对方的存在
  • 支持多对多通信,一个事件多个订阅者,一个订阅者多个事件
  • 高度灵活,可以动态添加/移除订阅
  • 支持跨模块、跨组件通信
  • 易于扩展,可以添加中间件、过滤器等

缺点:

  • 调试困难,事件流向不透明
  • 可能导致内存泄漏(订阅者未正确取消订阅)
  • 缺乏类型安全,事件名称和参数容易出错
  • 全局事件总线可能导致命名冲突
  • 过度使用会导致代码难以维护

适用场景:

  • 跨组件通信(如兄弟组件通信)
  • 插件系统
  • 微前端架构中的模块通信
  • 需要高度解耦的大型应用

Promise

Promise 是 ES6 引入的异步编程解决方案,表示一个异步操作的最终完成(或失败)及其结果值。

javascript
function fetchData(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    xhr.onload = function () {
      if (xhr.status === 200) {
        resolve(JSON.parse(xhr.responseText))
      } else {
        reject(new Error(`HTTP Error: ${xhr.status}`))
      }
    }
    xhr.onerror = function () {
      reject(new Error('Network Error'))
    }
    xhr.send()
  })
}

// 链式调用
fetchData('/api/user')
  .then(user => fetchData(`/api/posts?userId=${user.id}`))
  .then(posts => console.log(posts))
  .catch(err => console.error(err))
  .finally(() => console.log('Request complete'))

// Promise 并行
Promise.all([fetchData('/api/user'), fetchData('/api/posts')])
  .then(([user, posts]) => console.log(user, posts))
  .catch(err => console.error(err))

// Promise 竞速
Promise.race([
  fetchData('/api/fast'),
  new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), 5000)
  )
])
  .then(data => console.log(data))
  .catch(err => console.error(err))

优点:

  • 解决了回调地狱问题,通过链式调用使代码扁平化
  • 统一的错误处理,通过 .catch() 集中捕获异常
  • 支持链式调用,代码可读性好
  • 提供丰富的静态方法:Promise.allPromise.racePromise.allSettledPromise.any
  • 状态不可逆(pending → fulfilled / rejected),行为可预测
  • 支持异步操作的组合和编排

缺点:

  • 一旦创建无法取消(Promise 缺乏内置的取消机制)
  • 内部错误如果不设置 .catch() 会被静默吞掉
  • 链式调用仍然不如同步代码直观
  • 调试不便,无法像同步代码一样设置断点逐步调试
  • 多个 .then() 仍然会产生一定的嵌套感

适用场景:

  • 网络请求(fetch、axios)
  • 文件操作
  • 定时器封装
  • 需要组合多个异步操作的场景
  • 现代前端/Node.js 项目的标准异步方案

Generator 函数

Generator 函数是 ES6 引入的,可以通过 yield 关键字暂停和恢复函数执行,天然适合处理异步流程。

javascript
function* fetchUser() {
  try {
    const user = yield fetch('/api/user').then(r => r.json())
    console.log('User:', user)

    const posts = yield fetch(`/api/posts?userId=${user.id}`).then(r =>
      r.json()
    )
    console.log('Posts:', posts)

    return posts
  } catch (err) {
    console.error('Error:', err)
  }
}

// 手动执行 Generator
const gen = fetchUser()
gen.next().value.then(user => {
  gen.next(user).value.then(posts => {
    gen.next(posts)
  })
})

// 使用执行器自动执行
function run(generator) {
  const gen = generator()

  function step(arg) {
    let result
    try {
      result = gen.next(arg)
    } catch (err) {
      return Promise.reject(err)
    }
    if (result.done) return Promise.resolve(result.value)
    return Promise.resolve(result.value).then(step, err =>
      step(Promise.reject(err))
    )
  }

  return step()
}

run(fetchUser).then(console.log)

优点:

  • 异步代码看起来像同步代码,可读性极佳
  • 拥有完整的函数语义(函数名、参数、返回值)
  • 可以暂停执行,实现惰性求值
  • 支持双向通信(通过 next() 传值和 yield 返回值)
  • 灵活性高,可以手动控制执行流程
  • 是 async/await 的底层实现基础

缺点:

  • 需要额外的执行器(co、run)才能自动管理异步流程
  • 学习曲线陡峭,概念较多(Iterator Protocol、yield、next)
  • 手动执行时代码仍然复杂
  • 与其他异步方案混用时容易混乱
  • 调试支持不如 async/await
  • 实际开发中已被 async/await 大量替代

适用场景:

  • 惰性序列生成(如斐波那契数列、无限序列)
  • 异步流程控制库的底层实现
  • 需要精细控制执行步骤的场景
  • 实现迭代器模式

async / await

async/await 是 ES2017 引入的语法糖,基于 Promise 实现,让异步代码看起来和同步代码完全一致。

javascript
async function fetchUserData() {
  try {
    const userResponse = await fetch('/api/user')
    const user = await userResponse.json()

    const postsResponse = await fetch(`/api/posts?userId=${user.id}`)
    const posts = await postsResponse.json()

    return { user, posts }
  } catch (err) {
    console.error('Failed to fetch user data:', err)
    throw err
  }
}

// 并行执行
async function fetchAllData() {
  try {
    const [users, posts] = await Promise.all([
      fetch('/api/users').then(r => r.json()),
      fetch('/api/posts').then(r => r.json())
    ])
    return { users, posts }
  } catch (err) {
    console.error(err)
  }
}

// 顶层 await(ES2022)
const data = await fetch('/api/data').then(r => r.json())

优点:

  • 代码可读性最佳,几乎与同步代码一致
  • 支持标准的 try/catch 错误处理
  • 调试友好,可以像同步代码一样设置断点
  • 语法简洁,学习成本低
  • 与 Promise 完全兼容,可以混用
  • 现代浏览器和 Node.js 全面支持
  • 支持顶层 await(ES2022)

缺点:

  • 连续的 await 会串行执行,可能影响性能(需要手动用 Promise.all 并行化)
  • 错误堆栈可能不如纯 Promise 清晰
  • 在循环中使用 await 可能导致性能问题
  • 无法取消(继承自 Promise 的限制)
  • 不适合事件驱动的持续异步流

适用场景:

  • 现代前端和 Node.js 项目的首选异步方案
  • 需要顺序执行多个异步操作
  • 需要 try/catch 错误处理的场景
  • API 调用、数据库操作等常规异步任务
  • React Hooks 中的数据获取

Promise 静态方法进阶

ES2020 引入了 Promise.allSettledPromise.any,与 ES6 的 Promise.allPromise.race 一起提供了丰富的异步编排能力。

javascript
// Promise.all - 全部成功才成功,一个失败即失败
const results = await Promise.all([
  fetch('/api/user').then(r => r.json()),
  fetch('/api/posts').then(r => r.json())
])

// Promise.allSettled - 等待全部完成(无论成功失败)
const settled = await Promise.allSettled([
  fetch('/api/service1').then(r => r.json()),
  fetch('/api/service2').then(r => r.json()),
  fetch('/api/service3').then(r => r.json())
])

settled.forEach(result => {
  if (result.status === 'fulfilled') {
    console.log('Success:', result.value)
  } else {
    console.log('Failed:', result.reason)
  }
})

// Promise.any - 任意一个成功即成功
const fastest = await Promise.any([
  fetch('/api/cdn1/data').then(r => r.json()),
  fetch('/api/cdn2/data').then(r => r.json()),
  fetch('/api/cdn3/data').then(r => r.json())
])

// Promise.race - 任意一个完成(成功或失败)即返回
const raceResult = await Promise.race([
  fetch('/api/data').then(r => r.json()),
  new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), 3000)
  )
])

优点:

  • Promise.all:适合需要所有异步操作都成功的场景
  • Promise.allSettled:适合需要知道每个操作结果的场景,不会因为某个失败而中断
  • Promise.any:适合冗余请求、竞速获取最快响应的场景
  • Promise.race:适合超时控制、竞速场景

缺点:

  • Promise.all:一个失败全部失败,无法获取成功的结果
  • Promise.allSettled:需要手动判断每个结果的状态
  • Promise.any:所有都失败时返回 AggregateError,处理较复杂
  • Promise.race:无法取消其他未完成的 Promise(可能导致资源浪费)

适用场景:

  • Promise.all:批量数据加载、并行 API 请求
  • Promise.allSettled:批量操作容错、健康检查
  • Promise.any:CDN 竞速、多数据源容灾
  • Promise.race:请求超时控制

异步迭代器(Async Iterator)

ES2018 引入了异步迭代器和 for await...of 循环,用于处理异步数据流。

javascript
// 异步生成器
async function* fetchPaginatedData(url) {
  let page = 1
  while (true) {
    const response = await fetch(`${url}?page=${page}`)
    const data = await response.json()
    if (data.items.length === 0) break
    yield data.items
    page++
  }
}

// for await...of 消费异步迭代器
async function processAllPages() {
  for await (const items of fetchPaginatedData('/api/posts')) {
    console.log(`Processing ${items.length} items`)
    items.forEach(item => processItem(item))
  }
}

// Node.js Readable Stream 异步迭代
const fs = require('fs')
const readline = require('readline')

async function processFile(filePath) {
  const stream = fs.createReadStream(filePath)
  const rl = readline.createInterface({ input: stream })

  for await (const line of rl) {
    console.log('Line:', line)
  }
}

优点:

  • 天然处理分页、流式数据等持续产生的异步数据
  • for...of 语法一致,学习成本低
  • 支持惰性求值,按需加载数据
  • 与 Node.js Stream 完美结合
  • 内存效率高,不需要一次性加载所有数据

缺点:

  • 浏览器支持相对较新(IE 完全不支持)
  • 错误处理需要在循环外部 try/catch
  • 无法直接并行处理(每次只处理一个元素)
  • 调试异步生成器比较困难
  • 中断循环需要使用 break 或 throw

适用场景:

  • 分页数据加载
  • Node.js Stream 处理
  • SSE(Server-Sent Events)消费
  • WebSocket 消息流处理
  • 大文件逐行读取

Web Workers

Web Workers 允许在后台线程中运行 JavaScript,不会阻塞主线程,适合处理 CPU 密集型任务。

javascript
// 主线程 main.js
const worker = new Worker('worker.js')

worker.postMessage({ type: 'start', data: largeDataSet })

worker.onmessage = function (e) {
  console.log('Result from worker:', e.data)
}

worker.onerror = function (err) {
  console.error('Worker error:', err)
}

// worker.js
self.onmessage = function (e) {
  if (e.data.type === 'start') {
    const result = heavyComputation(e.data.data)
    self.postMessage({ type: 'result', data: result })
  }
}

function heavyComputation(data) {
  // 耗时计算...
  return processedData
}

优点:

  • 不阻塞主线程,保持 UI 流畅
  • 真正的并行计算,利用多核 CPU
  • 独立的运行环境,不影响主线程变量
  • 适合 CPU 密集型任务(图像处理、数据分析等)
  • 支持多个 Worker 并行

缺点:

  • 无法直接操作 DOM
  • 通信开销(通过 postMessage 序列化/反序列化)
  • 创建 Worker 有性能开销,不适合短任务
  • 调试困难(Chrome DevTools 支持有限)
  • 同源限制,Worker 脚本必须与主页面同源
  • 增加了代码复杂度

适用场景:

  • 大数据计算和分析
  • 图像/视频处理
  • 加密/解密操作
  • 复杂的数学运算
  • 文件处理(如 CSV/JSON 大文件解析)

RxJS(响应式编程)

RxJS 是 Reactive Extensions 的 JavaScript 实现,使用 Observable 序列来处理异步数据流和事件组合。

javascript
import { fromEvent, debounceTime, map, switchMap, catchError, of } from 'rxjs'
import { ajax } from 'rxjs/ajax'

// 搜索框自动补全
const searchInput = document.getElementById('search')

fromEvent(searchInput, 'input')
  .pipe(
    debounceTime(300),
    map(event => event.target.value),
    switchMap(query =>
      ajax.getJSON(`/api/search?q=${query}`).pipe(catchError(() => of([])))
    )
  )
  .subscribe(results => {
    renderResults(results)
  })

// 定时器
import { interval, take, filter } from 'rxjs'

interval(1000)
  .pipe(
    take(5),
    filter(value => value % 2 === 0)
  )
  .subscribe(value => console.log(value)) // 0, 2, 4

优点:

  • 强大的数据流处理能力,支持丰富的操作符
  • 内置背压处理、取消订阅等机制
  • 声明式编程,代码简洁
  • 完美处理高频事件(如搜索输入、滚动、窗口调整)
  • 支持复杂的异步操作组合
  • 错误处理和重试机制完善

缺点:

  • 学习曲线非常陡峭,概念众多(Observable、Observer、Subject、Operator 等)
  • 调试困难,数据流不透明
  • 库体积较大(即使 tree-shaking 后也有一定体积)
  • 过度使用会导致代码可读性下降
  • 团队协作时需要所有成员都熟悉 RxJS
  • 在简单场景下显得过于复杂

适用场景:

  • 高频事件处理(搜索、滚动、拖拽)
  • 复杂的异步数据流组合
  • 实时数据推送(WebSocket、SSE)
  • Angular 项目(Angular 内置使用 RxJS)
  • 需要取消、重试、节流等复杂控制的场景

Node.js Stream

Node.js Stream 是处理流式数据的异步方案,支持四种流类型:Readable、Writable、Duplex、Transform。

javascript
const fs = require('fs')
const { pipeline } = require('stream/promises')
const { Transform } = require('stream')

// 文件复制
async function copyFile(src, dest) {
  await pipeline(fs.createReadStream(src), fs.createWriteStream(dest))
}

// 数据转换流
const upperCase = new Transform({
  transform(chunk, encoding, callback) {
    callback(null, chunk.toString().toUpperCase())
  }
})

fs.createReadStream('input.txt')
  .pipe(upperCase)
  .pipe(fs.createWriteStream('output.txt'))

// 异步迭代器方式消费
async function processStream() {
  const stream = fs.createReadStream('large-file.txt', {
    highWaterMark: 64 * 1024
  })
  stream.setEncoding('utf-8')

  for await (const chunk of stream) {
    console.log('Chunk:', chunk)
  }
}

优点:

  • 内存效率极高,不需要一次性加载全部数据
  • 支持背压机制,自动调节数据流速
  • 可以通过 .pipe() 优雅地组合多个流
  • 适合处理大文件和网络数据
  • Node.js 核心模块,无需额外依赖

缺点:

  • 仅限 Node.js 环境,浏览器不直接支持
  • 错误处理比较复杂(尤其是管道中的错误传播)
  • 调试困难,数据在管道中流动不透明
  • 某些流类型(如 Transform)编写较复杂
  • 旧版 Node.js 的 Stream API 与新版不完全兼容

适用场景:

  • 大文件读写和处理
  • 网络数据传输(HTTP 请求/响应)
  • 日志处理
  • 数据压缩/解压
  • 视频音频处理

定时器(setTimeout / setInterval)

JavaScript 的定时器是最简单的异步机制,用于延迟或重复执行代码。

javascript
// setTimeout - 延迟执行
setTimeout(() => {
  console.log('Executed after 1 second')
}, 1000)

// setInterval - 重复执行
const timer = setInterval(() => {
  console.log('Executed every second')
}, 1000)

// 清除定时器
clearInterval(timer)

// setTimeout 模拟 setInterval(避免重叠)
function repeat(fn, delay) {
  setTimeout(function loop() {
    fn()
    setTimeout(loop, delay)
  }, delay)
}

// Promise 化定时器
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function main() {
  console.log('Start')
  await delay(1000)
  console.log('After 1 second')
}

优点:

  • API 简单,使用方便
  • 所有 JavaScript 环境都支持
  • 适合简单的延时和轮询场景
  • 与 Promise 结合使用非常灵活

缺点:

  • 最小延迟约 4ms(浏览器中嵌套超过 5 层时)
  • 不保证精确的时间间隔(受事件循环影响)
  • setInterval 可能出现回调重叠问题
  • 在非活动标签页中,浏览器可能降低定时器精度(甚至暂停)
  • 不适合需要精确计时的场景

适用场景:

  • 简单的延时操作
  • 轮询检查状态
  • 动画和视觉效果
  • 防抖/节流的底层实现
  • 超时控制

requestAnimationFrame

requestAnimationFrame 是浏览器提供的专门用于动画的异步 API,会在下一次重绘之前调用指定的回调函数。

javascript
// 基本动画
function animate() {
  // 更新动画状态
  update()

  // 重绘
  draw()

  // 下一帧继续
  requestAnimationFrame(animate)
}

requestAnimationFrame(animate)

// Promise 化
function nextFrame() {
  return new Promise(resolve => requestAnimationFrame(resolve))
}

async function smoothScroll(element, target) {
  while (Math.abs(element.scrollTop - target) > 1) {
    element.scrollTop += (target - element.scrollTop) * 0.1
    await nextFrame()
  }
  element.scrollTop = target
}

优点:

  • 与浏览器刷新率同步(通常 60fps),动画流畅
  • 在标签页不可见时自动暂停,节省资源
  • 浏览器会自动优化渲染时机
  • 比 setTimeout 动画性能更好、更流畅

缺点:

  • 仅限浏览器环境
  • 回调函数只接收一个 timestamp 参数
  • 无法指定延迟时间
  • 不适合非动画类的异步操作

适用场景:

  • Canvas 动画
  • DOM 动画(滚动、过渡效果)
  • 游戏循环
  • 视觉效果和粒子系统

MutationObserver

MutationObserver 是浏览器提供的用于监视 DOM 变化的异步 API。

javascript
const observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    switch (mutation.type) {
      case 'childList':
        console.log('Child nodes changed')
        break
      case 'attributes':
        console.log(`Attribute ${mutation.attributeName} changed`)
        break
      case 'characterData':
        console.log('Text content changed')
        break
    }
  })
})

observer.observe(targetNode, {
  childList: true,
  attributes: true,
  characterData: true,
  subtree: true
})

// 停止观察
observer.disconnect()

优点:

  • 异步批量处理 DOM 变化,性能优于 Mutation Events
  • 可以精确配置观察范围(子节点、属性、文本等)
  • 支持获取变化记录的详细信息
  • 不会阻塞 DOM 操作

缺点:

  • 仅限浏览器环境
  • API 相对复杂
  • 在大量 DOM 变化时可能产生性能问题
  • 需要手动 disconnect 避免内存泄漏

适用场景:

  • 监听第三方库对 DOM 的修改
  • 实现自定义组件的响应式更新
  • 调试 DOM 变化
  • 实现虚拟 DOM 的差异检测

IntersectionObserver

IntersectionObserver 用于异步观察目标元素与其祖先元素或顶级文档视口的交叉状态。

javascript
const observer = new IntersectionObserver(
  entries => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log('Element is visible')
        loadContent(entry.target)
        observer.unobserve(entry.target)
      }
    })
  },
  {
    root: null,
    threshold: 0.1,
    rootMargin: '100px'
  }
)

document.querySelectorAll('.lazy-load').forEach(el => {
  observer.observe(el)
})

优点:

  • 性能远优于监听 scroll 事件 + getBoundingClientRect
  • 异步执行,不阻塞主线程
  • 浏览器内部优化,无需手动计算
  • 配置灵活(阈值、根元素、边距)

缺点:

  • 仅限浏览器环境
  • 无法获取精确的滚动位置
  • 兼容性:IE 不支持(需要 polyfill)
  • 某些复杂场景(如水平滚动嵌套)支持有限

适用场景:

  • 图片懒加载
  • 无限滚动
  • 元素曝光统计
  • 广告可见性检测
  • 滚动动画触发

AbortController(取消异步操作)

AbortController 是现代浏览器和 Node.js 提供的用于取消异步操作的 API。

javascript
// 取消 fetch 请求
const controller = new AbortController()
const signal = controller.signal

fetch('/api/data', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('Request was cancelled')
    } else {
      console.error(err)
    }
  })

// 3 秒后取消
setTimeout(() => controller.abort(), 3000)

// 取消多个请求
function createFetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController()
  const id = setTimeout(() => controller.abort(), timeout)

  return fetch(url, { signal: controller.signal }).finally(() =>
    clearTimeout(id)
  )
}

优点:

  • 标准化的取消机制,可取消 fetch、EventTarget 监听等
  • 避免不必要的网络请求和资源消耗
  • 支持取消多个关联的异步操作
  • 与 Promise、EventTarget 等原生 API 深度集成

缺点:

  • 需要异步 API 显式支持 signal 参数
  • 一旦取消不可恢复
  • 兼容性:IE 不支持,旧版浏览器需要 polyfill
  • 需要手动管理 AbortController 生命周期

适用场景:

  • 取消未完成的 fetch 请求
  • 搜索输入时的请求去重(取消上一次请求)
  • 组件卸载时清理异步操作
  • 请求超时控制
  • 用户主动取消长时间操作

各方案对比总结

方案引入版本可读性错误处理取消支持适用环境学习成本
回调函数ES3需手动全部
事件监听DOM Level 2需手动浏览器/Node.js
发布订阅自定义实现需手动全部
PromiseES6不支持全部
GeneratorES6支持全部
async/awaitES2017最佳最佳不支持全部
Promise 静态方法ES2020不支持全部
异步迭代器ES2018break全部
Web WorkersHTML5terminate浏览器
RxJS第三方库unsubscribe全部很高
Node.js StreamNode.js 核心destroyNode.js
定时器ES3clearTimeout全部
requestAnimationFrame浏览器 APIcancelAnimationFrame浏览器
MutationObserverDOM Level 4disconnect浏览器
IntersectionObserver浏览器 APIunobserve浏览器
AbortControllerDOM/Node.jsabort全部

基于 VitePress 的本地知识库