JavaScript异步,笔记250810

84 阅读30分钟

JavaScript异步,笔记250810

JavaScript 异步编程全面解析

一、异步编程基础

     为什么需要异步编程? JavaScript 是单线程语言,异步操作可以防止阻塞主线程:

  • 处理网络请求
  • 执行文件 I/O
  • 管理定时任务
  • 响应用户交互
// 同步阻塞示例
console.log("开始");
alert("阻塞操作"); // 阻塞主线程
console.log("结束");

// 异步非阻塞示例
console.log("开始");
setTimeout(() => console.log("异步操作"), 0);
console.log("结束");
// 输出:开始 → 结束 → 异步操作

     事件循环机制 JavaScript 引擎通过事件循环处理异步操作:

graph LR
    A[调用栈] --> B{调用栈为空?}
    B -->|是| C[事件队列]
    C --> D[取第一个任务]
    D --> E[执行任务]
    E --> A
    B -->|否| A

二、异步解决方案演进

     1. 回调函数(Callback)

function fetchData(callback) {
  setTimeout(() => callback('数据'), 1000);
}

fetchData(data => console.log(data));

回调地狱问题

getUser(id, user => {
  getProfile(user.id, profile => {
    getOrders(profile.id, orders => {
      renderUI(user, profile, orders);
    }, handleError);
  }, handleError);
}, handleError);

     2. Promise(ES6)

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 
        ? resolve('成功数据') 
        : reject('请求失败');
    }, 1000);
  });
}

fetchData()
  .then(data => console.log(data))
  .catch(err => console.error(err));

     3. async/await(ES2017)

async function loadData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

三、Promise 深度解析

     Promise 生命周期

stateDiagram-v2
    [*] --> Pending
    Pending --> Fulfilled: resolve()
    Pending --> Rejected: reject()
    Fulfilled --> [*]
    Rejected --> [*]

     核心方法

// 链式调用
fetchData()
  .then(process)
  .then(save)
  .catch(handleError)
  .finally(cleanup);

// 并行执行
Promise.all([task1, task2, task3])
  .then(results => console.log(results));

// 竞速执行
Promise.race([fastSource, slowSource])
  .then(firstResult => use(firstResult));

// 全完成执行
Promise.allSettled([successTask, failTask])
  .then(results => results.forEach(handleResult));

四、async/await 最佳实践

     基础用法

async function getUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const orders = await fetchOrders(user.id);
    return { user, orders };
  } catch (error) {
    console.error("获取数据失败:", error);
    return { user: null, orders: [] };
  } finally {
    console.log("请求完成");
  }
}

     优化技巧

// 顺序 vs 并行
async function getData() {
  // 顺序执行 (慢)
  const a = await fetchA();
  const b = await fetchB();
  
  // 并行执行 (快)
  const [c, d] = await Promise.all([fetchC(), fetchD()]);
  
  return { a, b, c, d };
}

// 尽早启动请求
async function optimizedLoad() {
  const userPromise = fetchUser(); // 立即启动
  const config = await fetchConfig(); // 等待配置
  const user = await userPromise;   // 等待用户数据
  
  return { user, config };
}

五、高级异步模式

     1. 取消异步操作

function cancellableFetch(url) {
  const controller = new AbortController();
  const promise = fetch(url, { 
    signal: controller.signal 
  });
  
  return {
    promise,
    cancel: () => controller.abort()
  };
}

// 使用
const { promise, cancel } = cancellableFetch('/api/data');
cancelButton.onclick = cancel;

try {
  const data = await promise;
} catch (err) {
  if (err.name === 'AbortError') {
    console.log('请求已取消');
  }
}

     2. 自动重试机制

async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fetch(url);
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 1000 * (i + 1))); // 指数退避
    }
  }
}

     3. 并发控制

async function parallelWithLimit(tasks, limit = 5) {
  const results = [];
  const executing = new Set();
  
  for (const task of tasks) {
    const p = task().then(result => {
      results.push(result);
      executing.delete(p);
    });
    
    executing.add(p);
    
    if (executing.size >= limit) {
      await Promise.race(executing);
    }
  }
  
  await Promise.all(executing);
  return results;
}

// 使用
const tasks = Array(10).fill(() => fetchData());
const results = await parallelWithLimit(tasks, 3);

六、错误处理策略

     分层错误处理

async function purchaseProduct(userId, productId) {
  try {
    const user = await validateUser(userId);
  } catch (err) {
    if (err.code === 'USER_INVALID') {
      return { success: false, reason: '用户无效' };
    }
    throw err; // 重新抛出未知错误
  }
  
  try {
    await deductBalance(userId, productId);
    await deliverProduct(productId);
    return { success: true };
  } catch (err) {
    await rollbackTransaction();
    logError(err);
    throw new Error('购买失败');
  }
}

     全局错误捕获

// 浏览器
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的Promise拒绝:', event.reason);
  event.preventDefault();
});

// Node.js
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的拒绝:', reason);
});

七、性能优化技巧

     1. 避免阻塞事件循环

// 分解长任务
async function processLargeData() {
  for (let i = 0; i < 100; i++) {
    await processChunk(i);
    await yieldToEventLoop(); // 让出事件循环
  }
}

function yieldToEventLoop() {
  return new Promise(resolve => setTimeout(resolve, 0));
}

     2. 内存管理

// 及时释放资源
async function loadImage(url) {
  const response = await fetch(url);
  const blob = await response.blob();
  const img = new Image();
  img.src = URL.createObjectURL(blob);
  
  // 使用后释放内存
  img.onload = () => URL.revokeObjectURL(img.src);
  return img;
}

八、实战应用示例

     实时搜索优化

let searchController = null;

async function handleSearch(query) {
  // 取消之前的请求
  if (searchController) searchController.abort();
  
  const controller = new AbortController();
  searchController = controller;
  
  try {
    const response = await fetch(`/search?q=${query}`, {
      signal: controller.signal
    });
    const results = await response.json();
    displayResults(results);
  } catch (err) {
    if (err.name !== 'AbortError') {
      showError('搜索失败');
    }
  }
}

     表单提交处理

async function handleSubmit(e) {
  e.preventDefault();
  
  const submitBtn = e.target.querySelector('button[type="submit"]');
  submitBtn.disabled = true;
  
  try {
    const formData = new FormData(e.target);
    const response = await fetch('/submit', {
      method: 'POST',
      body: formData
    });
    
    if (!response.ok) throw new Error('提交失败');
    
    showSuccess();
  } catch (err) {
    showError(err.message);
  } finally {
    submitBtn.disabled = false;
  }
}

九、常见陷阱与解决方案

     1. 异步循环问题

// 错误:顺序执行异步循环
async function processArray(array) {
  for (const item of array) {
    await processItem(item); // 顺序执行,效率低
  }
}

// 正确:并行处理
async function processArray(array) {
  await Promise.all(array.map(item => processItem(item)));
}

     2. Promise 创建陷阱

// 错误:立即执行异步操作
const promises = [fetchA, fetchB].map(fn => {
  return new Promise(resolve => {
    fn().then(resolve); // 不必要的 Promise 包装
  });
});

// 正确:直接返回 Promise
const promises = [fetchA(), fetchB()];

     3. async/await 误用

// 错误:不必要的 async
async function getConfig() {
  return { setting: 'value' }; // 自动包装为 Promise
}

// 正确:直接返回值
function getConfig() {
  return { setting: 'value' };
}

十、现代异步编程总结

     技术选型指南

场景推荐方案
简单异步操作Promise 或 async/await
复杂异步流程async/await + try/catch
并行多个独立请求Promise.all + await
需要取消的操作AbortController + Promise
流式数据处理异步迭代器 (for-await-of)
高并发控制自定义并发池
需要重试的操作递归 async 函数

     终极最佳实践

async function optimalAsyncWorkflow() {
  // 1. 并行加载独立数据
  const [user, config] = await Promise.all([
    fetchUser(),
    fetchConfig()
  ]);
  
  // 2. 顺序执行依赖操作
  const profile = await fetchProfile(user.id);
  
  // 3. 后台执行非关键任务
  sendAnalytics(user).catch(logError);
  
  // 4. 返回关键数据
  return { user, profile, config };
}

// 5. 全局错误处理
optimalAsyncWorkflow()
  .then(renderUI)
  .catch(showErrorScreen)
  .finally(cleanupResources);

掌握 JavaScript 异步编程需要理解:

  1. 事件循环机制
  2. Promise 原理和链式调用
  3. async/await 执行流程
  4. 错误处理策略
  5. 性能优化技巧

通过合理选择异步模式并遵循最佳实践,可以构建高性能、可维护的 JavaScript 应用。

















1️⃣ 参考 1

JavaScript 异步编程是处理非阻塞操作的核心机制,以下是关键知识点和最佳实践总结:


     异步编程的必要性 JavaScript 是单线程语言,异步模型避免阻塞主线程:

  • 网络请求(fetch
  • 文件操作(Node.js)
  • 定时任务(setTimeout/setInterval
  • 用户交互事件(点击/滚动)

     核心解决方案演进

方案特点代码示例
回调函数基础方案,易产生回调地狱fs.readFile('file.txt', callback)
Promise链式调用,解决嵌套问题fetch(url).then().catch()
async/await同步写法,最佳可读性const data = await fetch()

     Promise 深度解析

// 创建 Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("成功!"), 1000);
});

// 使用链式调用
promise
  .then(result => result + " 再处理")
  .then(final => console.log(final)) // "成功! 再处理"
  .catch(err => console.error(err));

关键方法

  • Promise.all([...]):并行执行,全部成功
  • Promise.race([...]):竞速,第一个完成的结果
  • Promise.any([...]):第一个成功的值
  • Promise.allSettled([...]):所有结果(无论成败)

     async/await 最佳实践

async function loadData() {
  try {
    const user = await fetchUser();
    const posts = await fetchPosts(user.id); 
    return { user, posts };
  } catch (error) {
    console.error("加载失败:", error);
    throw error; // 重新抛出错误
  } finally {
    console.log("清理资源");
  }
}

// 使用
loadData().then(data => renderUI(data));

使用技巧

  1. try/catch 替代 .catch()
  2. 避免在循环中误用 await(需并行时用 Promise.all
    // 错误:顺序执行(慢)
    for (const url of urls) await fetch(url);
    
    // 正确:并行执行
    await Promise.all(urls.map(url => fetch(url)));
    

     事件循环(Event Loop)机制 JavaScript 运行时模型:

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

Promise.resolve()
  .then(() => console.log("Microtask 1"))
  .then(() => console.log("Microtask 2"));

console.log("End");

/* 输出顺序:
   Start 
   End 
   Microtask 1 
   Microtask 2 
   Timeout
*/

执行优先级

  1. 同步代码(主线程)
  2. 微任务(Microtasks):
    • Promise 回调
    • queueMicrotask()
    • MutationObserver
  3. 宏任务(Macrotasks):
    • setTimeout/setInterval
    • I/O 操作
    • UI 渲染

     常见陷阱与解决方案

  1. 回调地狱 → 用 Promise 链或 async/await 扁平化
  2. 未处理的拒绝 → 添加 .catch() 或全局错误监听
    process.on('unhandledRejection', error => { /* 处理 */ });
    
  3. 并发控制 → 限制并行数量
    // 使用 p-limit 库
    const limit = pLimit(3); // 最大并发数
    await Promise.all(items.map(item => 
      limit(() => processItem(item))
    );
    

     现代异步模式

  1. 异步迭代(Async Iteration):
    for await (const chunk of readableStream) {
      console.log(chunk);
    }
    
  2. Web Workers
    const worker = new Worker('task.js');
    worker.postMessage(data);
    worker.onmessage = e => handle(e.data);
    
  3. 响应式编程(RxJS):
    import { fromEvent } from 'rxjs';
    fromEvent(button, 'click')
      .pipe(throttleTime(1000))
      .subscribe(() => handleClick());
    

     最佳实践总结

  1. 首选 async/await 编写异步逻辑
  2. 并行任务用 Promise.all() 而非顺序 await
  3. 始终处理错误(try/catch.catch()
  4. 避免阻塞事件循环(长任务拆分为微任务)
  5. 复杂场景考虑 RxJS 或 Web Workers

示例:健壮的异步函数

async function fetchWithRetry(url, retries = 3) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response.json();
  } catch (error) {
    if (retries <= 0) throw error;
    await new Promise(resolve => setTimeout(resolve, 1000));
    return fetchWithRetry(url, retries - 1);
  }
}

















2️⃣ 参考 2

JavaScript 异步编程全面解析

JavaScript 作为单线程语言,通过异步机制实现非阻塞操作。以下是核心概念和解决方案的演进:


     异步编程的必要性

  • 避免阻塞主线程(UI 冻结)
  • 高效处理 I/O 操作(网络请求、文件读写)
  • 实现动画、实时交互等场景

     异步解决方案演进

         1. 回调函数(Callback)

// 回调地狱示例
getData(a => {
  processA(a, b => {
    processB(b, c => {
      processC(c) // 嵌套层级失控
    })
  })
})

痛点:回调地狱、错误处理困难

         2. Promise(ES6)

getData()
  .then(processA)
  .then(processB)
  .then(processC)
  .catch(handleError) // 统一错误处理

优势:链式调用、状态管理

         3. async/await(ES2017)

async function workflow() {
  try {
    const a = await getData()
    const b = await processA(a)
    const c = await processB(b)
    return processC(c)
  } catch (error) {
    handleError(error)
  }
}

优势:同步写法、try/catch 错误处理


     核心机制:事件循环(Event Loop)

在这里插入图片描述

         执行顺序规则

  1. 执行所有同步代码(调用栈)
  2. 执行微任务队列(Microtask Queue):
    • Promise 回调(then/catch/finally)
    • queueMicrotask()
    • MutationObserver
  3. 执行宏任务队列(Macrotask Queue):
    • setTimeout/setInterval
    • I/O 操作
    • UI 渲染
    • 事件回调
console.log("1. 同步");

setTimeout(() => console.log("4. 宏任务"), 0);

Promise.resolve()
  .then(() => console.log("3. 微任务"));

console.log("2. 同步");

// 输出:1 → 2 → 3 → 4

     关键异步模式

         1. 并行执行

// Promise.all:全部成功才算成功
const [user, posts] = await Promise.all([
  fetchUser(),
  fetchPosts()
]);

// Promise.allSettled:获取所有结果状态
const results = await Promise.allSettled([
  fetchA(),
  fetchB()
]);

         2. 竞速执行

// 第一个成功/失败的结果
const winner = await Promise.race([
  fetchFast(),
  fetchSlow()
]);

// 第一个成功的请求
const data = await Promise.any([
  backupAPI1(),
  backupAPI2()
]);

         3. 错误重试

async function retry(fn, retries = 3) {
  try {
    return await fn();
  } catch (err) {
    if (retries <= 0) throw err;
    await delay(1000);
    return retry(fn, retries - 1);
  }
}

     异步最佳实践

  1. 避免阻塞主线程

    // 将耗时任务拆解
    function chunkProcess() {
      doPart();
      setTimeout(chunkProcess, 0);
    }
    
  2. 优化 async/await

    // 并行替代顺序等待
    const [a, b] = await Promise.all([getA(), getB()]);
    
    // 提前启动请求
    const dataPromise = fetchData(); // 不阻塞
    processSync();
    const data = await dataPromise;
    
  3. 优雅取消异步

    const controller = new AbortController();
    
    fetch(url, { signal: controller.signal })
      .catch(err => {
        if (err.name === 'AbortError') return;
      });
    
    // 需要时取消
    controller.abort();
    
  4. 微任务优化

    // 批量更新 UI
    function batchUpdate() {
      queueMicrotask(() => {
        // 在此更新 DOM
      });
    }
    

     常见陷阱及解决

  1. 循环中的 await

    // ❌ 顺序执行(慢)
    for (const url of urls) {
      await fetch(url);
    }
    
    // ✅ 并行执行
    await Promise.all(urls.map(url => fetch(url)));
    
  2. 未处理的拒绝

    // 添加全局捕获
    process.on('unhandledRejection', err => {
      logError(err);
    });
    
  3. 上下文丢失

    // ❌ this 丢失
    user.getData().then(function(data) {
      this.render(data); // this ≠ user
    });
    
    // ✅ 箭头函数保留 this
    user.getData().then(data => this.render(data));
    

     现代异步工具

  • 顶层 await(ES2022):模块中直接使用 await
  • 异步迭代for await...of 处理流式数据
  • Web Workers:CPU 密集型任务并行处理
  • Atomics.waitAsync:高级并发控制

掌握 JavaScript 异步编程,能让你构建高性能、响应式的应用,同时避免回调地狱和性能瓶颈!

















3️⃣ 参考 3

JavaScript 异步编程全面解析

JavaScript 是单线程语言,异步编程是其核心特性,用于处理非阻塞操作(如网络请求、文件读写等)。以下是完整的异步解决方案演进:

     一、异步编程演进史

  1. 回调函数 (Callback):最基础的异步模式
  2. Promise:ES6 引入,解决"回调地狱"
  3. async/await:ES2017 引入,使异步代码像同步代码

     二、核心机制:事件循环 (Event Loop) JavaScript 通过事件循环处理异步操作:

console.log('Start'); // 同步任务

setTimeout(() => {
  console.log('Timeout'); // 异步宏任务
}, 0);

Promise.resolve().then(() => {
  console.log('Promise'); // 异步微任务
});

console.log('End'); // 同步任务

/* 输出顺序:
   Start
   End
   Promise (微任务优先)
   Timeout (宏任务)
*/

     三、异步解决方案详解

         1. 回调函数 (Callback)

function fetchData(callback) {
  setTimeout(() => {
    callback('Data received');
  }, 1000);
}

fetchData(data => {
  console.log(data); // 1秒后输出 "Data received"
});

问题:回调地狱 (Callback Hell)

getUser(userId, user => {
  getOrders(user.id, orders => {
    getProducts(orders[0].id, product => {
      // 嵌套层级越来越深...
    });
  });
});

         2. Promise (ES6)

const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (success) {
    resolve(value); // 成功状态
  } else {
    reject(error); // 失败状态
  }
});

// 使用示例
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error))
  .finally(() => console.log('Cleanup'));

         3. async/await (ES2017)

async function fetchUser() {
  try {
    const response = await fetch('/api/user');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch failed:', error);
    throw error; // 重新抛出错误
  } finally {
    console.log('Request completed');
  }
}

// 使用
(async () => {
  const user = await fetchUser();
  console.log('User:', user);
})();

     四、Promise 高级方法

方法描述使用场景
Promise.all()所有成功才成功,任一失败立即失败并行独立操作
Promise.allSettled()等待所有 Promise 完成需要知道所有结果
Promise.race()采用第一个完成的结果请求超时处理
Promise.any()采用第一个成功的结果多源数据获取
// 超时控制示例
const fetchWithTimeout = (url, timeout) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
};

     五、异步最佳实践

  1. 避免嵌套层级

    // 不良实践
    getUser().then(user => {
      getOrders(user.id).then(orders => {
        // ...
      });
    });
    
    // 最佳实践
    getUser()
      .then(user => getOrders(user.id))
      .then(orders => { /* ... */ });
    
  2. 并行优化

    // 顺序执行 (慢)
    async function sequential() {
      const a = await task1();
      const b = await task2();
      return [a, b];
    }
    
    // 并行执行 (快)
    async function parallel() {
      const [a, b] = await Promise.all([task1(), task2()]);
      return [a, b];
    }
    
  3. 错误处理

    // 集中错误处理
    async function main() {
      try {
        const user = await fetchUser();
        const orders = await fetchOrders(user.id);
        // ...
      } catch (error) {
        // 统一处理所有错误
        logError(error);
        showUserMessage('操作失败');
      }
    }
    

     六、现代异步模式

  1. 顶层 await (ES2022)

    // 模块中直接使用
    const data = await fetchData();
    console.log(data);
    
  2. 异步迭代器 (for-await-of)

    async function processStream(stream) {
      for await (const chunk of stream) {
        console.log('Received chunk:', chunk);
        processChunk(chunk);
      }
    }
    
  3. Web Workers 多线程

    // 主线程
    const worker = new Worker('task.js');
    worker.postMessage(data);
    worker.onmessage = e => console.log(e.data);
    
    // task.js
    self.onmessage = e => {
      const result = heavyComputation(e.data);
      self.postMessage(result);
    };
    

     七、异步调试技巧

  1. Async Stack Traces

    // Chrome DevTools 支持异步调用栈追踪
    async function foo() {
      await bar();
    }
    
    async function bar() {
      await baz(); // 错误时会显示完整调用链
    }
    
  2. console.async

    console.log('Start');
    await new Promise(r => setTimeout(r, 100));
    console.log('End'); // 控制台会显示异步时间线
    

     总结:选择指南

场景推荐方案
简单异步Promise.then
复杂逻辑async/await
并行请求Promise.all
错误优先async/await + try/catch
流处理for-await-of
CPU 密集型Web Workers

掌握这些异步技术组合使用,可以构建高效、可维护的 JavaScript 应用程序。记住:

  • 80% 场景使用 async/await
  • 并行操作使用 Promise.all
  • 始终处理错误(.catchtry/catch
  • 避免阻塞主线程

















4️⃣ 参考 4

在 JavaScript 中,异步编程是处理耗时操作(如网络请求、文件读写、定时器等)的核心机制,它允许代码在等待操作完成时继续执行,避免阻塞主线程。以下是 JavaScript 异步编程的核心概念和技术:


     1. 回调函数(Callbacks) 最早的异步处理方式,将函数作为参数传递给异步操作,完成后调用该函数。

setTimeout(() => {
  console.log("延时 1 秒后执行");
}, 1000);

缺点:嵌套过深会导致“回调地狱”(Callback Hell),代码难以维护。


     2. Promise ES6 引入,用于管理异步操作的状态(pending/fulfilled/rejected)。

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("数据获取成功");
      // 失败时:reject(new Error("请求失败"));
    }, 1000);
  });
};

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

优点:链式调用(.then().catch())解决回调地狱。


     3. Async/Await ES2017 语法糖,基于 Promise,用同步写法实现异步操作。

async function loadData() {
  try {
    const data = await fetchData(); // 等待 Promise 完成
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

loadData();

优点:代码更简洁,错误处理更直观(try/catch)。


     4. Event Loop(事件循环) JavaScript 单线程运行的核心机制,通过循环处理任务队列:

  1. 调用栈(Call Stack):执行同步任务。
  2. 任务队列(Task Queue)
    • 宏任务(Macrotasks)setTimeoutsetInterval、I/O。
    • 微任务(Microtasks)Promise.thenqueueMicrotaskMutationObserver
  3. 执行顺序
    • 同步代码 → 所有微任务 → 一个宏任务 → 重复。
console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

Promise.resolve()
  .then(() => console.log("Promise 1"))
  .then(() => console.log("Promise 2"));

console.log("End");

// 输出顺序:
// Start → End → Promise 1 → Promise 2 → Timeout

     5. 常见异步场景

  • 网络请求fetch API(返回 Promise)
    async function fetchUser() {
      const response = await fetch("https://api.example.com/user");
      const user = await response.json();
      console.log(user);
    }
    
  • 定时操作setTimeout/setInterval
  • 文件操作:Node.js 中的 fs.readFile
    const fs = require("fs/promises");
    fs.readFile("file.txt", "utf8").then(data => console.log(data));
    

     6. 错误处理

  • Promise:使用 .catch() 捕获异常。
  • Async/Await:用 try/catch 包裹。
  • 全局错误window.onerror(浏览器)或 process.on('unhandledRejection')(Node.js)。

     7. 进阶工具

  • Promise.all:并行执行多个 Promise,全部成功时返回结果数组。
    const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
    
  • Promise.race:返回最先完成的 Promise 结果。
  • Promise.allSettled:等待所有 Promise 完成(无论成功/失败)。

     关键总结

技术特点
回调函数基础但易嵌套过深,可读性差。
Promise链式调用解决回调地狱,状态不可逆。
Async/Await同步化写法,需搭配 try/catch 捕获错误。
Event Loop理解微任务/宏任务的执行顺序是掌握异步的核心。

掌握这些概念后,可高效处理 JavaScript 中的异步操作,编写出高性能、易维护的代码。

















5️⃣ 参考 5

JavaScript 异步编程全面指南

在 JavaScript 中,异步编程是处理非阻塞操作的核心机制。本文将系统介绍 JavaScript 异步编程的各种技术和最佳实践。

异步编程基础

     为什么需要异步? JavaScript 是单线程语言,异步编程可以:

  • 避免阻塞主线程,保持 UI 响应
  • 高效处理 I/O 密集型操作(网络请求、文件读写)
  • 管理定时任务和事件处理

     事件循环机制 JavaScript 通过事件循环处理异步操作:

graph LR
A[调用栈] --> B{栈空?}
B -->|是| C[事件队列]
C --> D[取第一个任务]
D --> E[执行任务]
E --> B

异步编程技术演进

     1. 回调函数(Callback) 最早的异步处理方式:

function fetchData(callback) {
  setTimeout(() => {
    callback('Data received');
  }, 1000);
}

fetchData((data) => {
  console.log(data); // 1秒后输出 "Data received"
});

问题:回调地狱

getUser(userId, (user) => {
  getProfile(user.id, (profile) => {
    getPosts(profile.id, (posts) => {
      renderPosts(posts, () => {
        // 更多嵌套...
      });
    });
  });
});

     2. Promise(ES6) Promise 提供了更结构化的异步处理:

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 ? 
        resolve('Success!') : 
        reject('Error occurred');
    }, 1000);
  });
};

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error))
  .finally(() => console.log('Operation completed'));

     3. async/await(ES2017) 基于 Promise 的语法糖,使异步代码更像同步代码:

async function fetchUserData() {
  try {
    const user = await getUser(userId);
    const profile = await getProfile(user.id);
    const posts = await getPosts(profile.id);
    return posts;
  } catch (error) {
    console.error('Failed to fetch data:', error);
    throw error;
  } finally {
    console.log('Data fetch completed');
  }
}

Promise 核心方法

     1. Promise.all 并行执行多个 Promise,全部成功时返回结果数组:

const loadAllData = async () => {
  try {
    const [users, posts, comments] = await Promise.all([
      fetch('/api/users'),
      fetch('/api/posts'),
      fetch('/api/comments')
    ]);
    console.log('All data loaded');
  } catch (error) {
    console.log('One request failed', error);
  }
};

     2. Promise.race 返回最先完成的 Promise:

const timeout = new Promise((_, reject) => 
  setTimeout(() => reject('Request timed out'), 5000)
);

const fetchWithTimeout = () => 
  Promise.race([
    fetch('/api/data'),
    timeout
  ]);

     3. Promise.allSettled 所有 Promise 完成后返回状态数组:

const promises = [
  fetch('/api/1'),
  fetch('/api/2'),
  fetch('/api/3')
];

Promise.allSettled(promises)
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Request ${index} succeeded`);
      } else {
        console.error(`Request ${index} failed:`, result.reason);
      }
    });
  });

高级异步模式

     1. 异步迭代器 处理流式数据或分页请求:

async function* asyncPaginator() {
  let page = 1;
  while (true) {
    const response = await fetch(`/api/items?page=${page}`);
    const data = await response.json();
    
    if (!data.items.length) break;
    
    yield data.items;
    page++;
  }
}

(async () => {
  for await (const items of asyncPaginator()) {
    items.forEach(item => console.log(item));
  }
})();

     2. 取消异步操作 使用 AbortController 取消请求:

const controller = new AbortController();

const fetchData = async () => {
  try {
    const response = await fetch('/api/data', {
      signal: controller.signal
    });
    return response.json();
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('Request was aborted');
    } else {
      throw error;
    }
  }
};

// 取消请求
document.getElementById('cancel-btn').addEventListener('click', () => {
  controller.abort();
});

     3. Web Workers 在后台线程执行 CPU 密集型任务:

// main.js
const worker = new Worker('worker.js');

worker.postMessage({ type: 'CALCULATE', data: largeArray });

worker.onmessage = (event) => {
  console.log('Result:', event.data);
};

// worker.js
self.onmessage = (event) => {
  if (event.data.type === 'CALCULATE') {
    const result = heavyComputation(event.data.data);
    self.postMessage(result);
  }
};

function heavyComputation(data) {
  // 复杂计算...
  return computedResult;
}

异步编程最佳实践

  1. 避免嵌套过深:使用 async/await 代替多层 then 链
  2. 并行独立操作:使用 Promise.all 提高效率
  3. 错误处理:始终使用 try/catch 或 catch 处理错误
  4. 资源清理:使用 finally 或 try/finally 确保资源释放
  5. 取消机制:为长时间操作实现取消功能
  6. 节流控制:使用库如 p-limit 控制并发请求数
  7. 超时处理:为不确定的操作添加超时机制

常见异步陷阱及解决方案

     陷阱1:在循环中错误使用 await

// 错误:顺序执行导致性能问题
async function processItems(items) {
  for (const item of items) {
    await process(item); // 每个操作等待前一个完成
  }
}

// 正确:并行处理
async function processItems(items) {
  await Promise.all(items.map(item => process(item)));
}

     陷阱2:忘记处理 Promise 拒绝

// 错误:未处理的 Promise 拒绝
async function riskyOperation() {
  const result = await fetchUnreliableApi();
  return result;
}

// 正确:添加错误处理
async function safeOperation() {
  try {
    const result = await fetchUnreliableApi();
    return result;
  } catch (error) {
    console.error('Operation failed:', error);
    return fallbackValue;
  }
}

     陷阱3:误解 async 函数返回值

async function getValue() {
  return 42; // 实际返回 Promise.resolve(42)
}

// 正确使用
getValue().then(value => console.log(value)); // 42

// 错误:直接当作同步值使用
const value = getValue(); // value 是 Promise 对象
console.log(value); // Promise {<fulfilled>: 42}

总结

JavaScript 异步编程经历了从回调函数到 Promise 再到 async/await 的演进,提供了越来越强大的工具来处理异步操作。关键要点包括:

  1. 理解事件循环是掌握异步编程的基础
  2. Promise 是核心,async/await 是其语法糖
  3. 组合使用 Promise.all/race/allSettled 处理复杂场景
  4. 错误处理至关重要,避免未处理的拒绝
  5. 高级模式如异步迭代器和取消机制解决特定问题
  6. Web Workers 处理 CPU 密集型任务

随着 JavaScript 的发展,异步编程变得更加简洁和强大,合理运用这些技术可以编写出高效、可维护的异步代码。

















6️⃣ 参考 6

JavaScript 异步编程全面指南

一、异步编程基础

     1. 为什么需要异步编程?

  • 单线程限制:JavaScript 是单线程语言,异步防止阻塞主线程
  • 性能优化:避免等待 I/O 操作(网络请求、文件读写等)
  • 用户体验:保持界面响应流畅
  • 资源效率:充分利用 CPU 和 I/O 资源

     2. 同步 vs 异步 示例

// 同步 - 阻塞执行
console.log("开始同步任务");
const result = networkRequestSync(); // 阻塞后续代码
console.log(result);
console.log("结束同步任务");

// 异步 - 非阻塞
console.log("开始异步任务");
networkRequestAsync(result => {
  console.log(result);
});
console.log("结束异步任务"); // 立即执行

二、异步演进史

时期技术特点
ES5 及之前回调函数简单但容易导致回调地狱
ES6 (2015)Promise链式调用,更好的错误处理
ES7 (2016)async/await同步风格编写异步代码
ES2018异步迭代器for-await-of 循环
现代浏览器Web Workers真正的并行执行

三、回调函数(Callback)

     基本模式

function fetchData(callback) {
  setTimeout(() => {
    callback('数据加载完成');
  }, 1000);
}

fetchData(result => {
  console.log(result);
});

     回调地狱问题

getUser(userId, user => {
  getProfile(user.id, profile => {
    getPosts(profile.id, posts => {
      renderPosts(posts, () => {
        notifyUser(() => {
          // 更多嵌套...
        });
      });
    });
  });
});

     解决方案

  1. 命名函数:避免匿名函数嵌套
    function handlePosts(posts) {
      renderPosts(posts);
    }
    
    function handleProfile(profile) {
      getPosts(profile.id, handlePosts);
    }
    
  2. 模块化:拆分功能为独立模块
  3. Promise:更先进的异步管理

四、Promise 核心机制

     Promise 状态机

stateDiagram-v2
    [*] --> Pending
    Pending --> Fulfilled: resolve()
    Pending --> Rejected: reject()
    Fulfilled --> [*]
    Rejected --> [*]

     创建 Promise

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    Math.random() > 0.5 ? 
      resolve('成功') : 
      reject(new Error('失败'));
  }, 1000);
});

     链式方法对比

方法作用返回值使用场景
.then()处理成功/失败新 Promise主要操作流程
.catch()捕获错误新 Promise全局错误处理
.finally()最终清理新 Promise资源清理,状态无关操作

五、async/await 革命

     基本用法

async function fetchUserData() {
  try {
    const user = await getUser();
    const posts = await getPosts(user.id);
    return { user, posts };
  } catch (error) {
    console.error("获取数据失败:", error);
    return null;
  }
}

     执行流程解析

sequenceDiagram
    participant Main as 主线程
    participant Async as async函数
    participant Promise
    
    Main->>Async: 调用异步函数
    Async->>Async: 执行同步代码
    Async->>Promise: await 暂停执行
    Main->>Main: 继续执行其他代码
    Promise-->>Async: Promise 解决
    Async->>Async: 恢复执行
    Async->>Main: 返回结果

六、高级异步模式

     1. 并行执行

// 顺序执行 (慢)
const user = await getUser();
const posts = await getPosts();

// 并行执行 (快)
const [user, posts] = await Promise.all([
  getUser(),
  getPosts()
]);

     2. 竞态控制

// 获取最快响应的数据源
const data = await Promise.race([
  fetchFromSourceA(),
  fetchFromSourceB()
]);

// 带超时的请求
async function fetchWithTimeout(url, timeout) {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('请求超时')), timeout)
    )
  ]);
}

     3. 异步迭代

async function processItems(items) {
  for await (const item of asyncIterator(items)) {
    await processItem(item);
  }
}

     4. 取消异步操作

function createCancellablePromise(promise) {
  let cancel;
  const wrapped = new Promise((resolve, reject) => {
    cancel = reject;
    promise.then(resolve).catch(reject);
  });
  return [wrapped, () => cancel(new Error('操作已取消'))];
}

// 使用
const [fetchPromise, cancel] = createCancellablePromise(fetchData());
cancelButton.addEventListener('click', cancel);

七、事件循环(Event Loop)详解

     JavaScript 运行时结构

graph LR
    HEAP[堆] -->|对象分配| ST[执行栈]
    WEB[Web APIs] -->|回调| TQ[任务队列]
    TQ --> EL[事件循环]
    EL --> ST

     执行顺序示例

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

// 输出顺序:1, 4, 3, 2

     任务类型

任务类型示例优先级
微任务Promise 回调
宏任务setTimeout, setInterval
渲染任务requestAnimationFrame

八、实际应用场景

     1. 数据获取与处理

async function loadDashboard() {
  try {
    const [user, stats, notifications] = await Promise.all([
      fetchUser(),
      fetchStats(),
      fetchNotifications()
    ]);
    
    return {
      user: processUser(user),
      stats: calculateMetrics(stats),
      notifications: filterImportant(notifications)
    };
  } catch (error) {
    showError(error);
    return loadCachedDashboard();
  }
}

     2. 文件上传进度

async function uploadFile(file, onProgress) {
  const formData = new FormData();
  formData.append('file', file);
  
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    
    xhr.upload.addEventListener('progress', e => {
      if (e.lengthComputable) {
        onProgress(Math.round((e.loaded / e.total) * 100));
      }
    });
    
    xhr.addEventListener('load', () => resolve(xhr.response));
    xhr.addEventListener('error', () => reject(new Error('上传失败')));
    
    xhr.open('POST', '/upload');
    xhr.send(formData);
  });
}

     3. 用户交互流程

async function purchaseFlow() {
  showLoading();
  
  try {
    const user = await verifyUser();
    const payment = await processPayment(user);
    const confirmation = await sendConfirmation(user, payment);
    
    return showSuccess(confirmation);
  } catch (error) {
    showError(error.message);
    return retryPurchase();
  } finally {
    hideLoading();
  }
}

九、常见问题与解决方案

     1. 回调地狱 → Promise链/async-await

// 回调地狱
getData(a => {
  processA(a, b => {
    processB(b, c => {
      processC(c);
    });
  });
});

// 解决方案
async function process() {
  const a = await getData();
  const b = await processA(a);
  const c = await processB(b);
  return processC(c);
}

     2. 未处理的拒绝 → 全局错误处理

// Node.js
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的拒绝:', reason);
});

// 浏览器
window.addEventListener('unhandledrejection', event => {
  console.error('未处理的拒绝:', event.reason);
});

     3. 并发控制

async function limitedConcurrency(tasks, limit) {
  const results = [];
  const executing = [];
  
  for (const task of tasks) {
    const p = task().then(result => {
      executing.splice(executing.indexOf(p), 1);
      return result;
    });
    
    results.push(p);
    executing.push(p);
    
    if (executing.length >= limit) {
      await Promise.race(executing);
    }
  }
  
  return Promise.all(results);
}

十、现代异步 API

     1. Fetch API

async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error('网络响应异常');
    return response.json();
  } catch (error) {
    console.error('请求失败:', error);
    return null;
  }
}

     2. Web Workers

// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ data: 'heavy computation' });
worker.onmessage = e => console.log('结果:', e.data);

// worker.js
self.onmessage = e => {
  const result = compute(e.data);
  self.postMessage(result);
};

     3. Async Clipboard API

async function copyText(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log('复制成功');
  } catch (err) {
    console.error('复制失败:', err);
  }
}

十一、最佳实践

  1. 优先 async/await:提高代码可读性
  2. 始终处理错误:使用 try/catch 或 .catch()
  3. 避免阻塞主线程:将重型计算移到 Web Worker
  4. 合理使用并行:Promise.all 优化独立操作
  5. 谨慎使用第三方库:了解其异步实现方式
  6. 监控未处理拒绝:设置全局错误处理器

十二、调试技巧

  1. 异步堆栈追踪

    async function main() {
      await step1();
    }
    
    async function step1() {
      await step2();
    }
    
    async function step2() {
      throw new Error('调试信息');
    }
    
    main().catch(console.error);
    
  2. console异步标记

    console.time('API请求');
    const data = await fetchData();
    console.timeEnd('API请求'); // 输出执行时间
    
  3. 浏览器调试工具

    • Async 调用栈视图
    • Promise 状态检查器
    • 网络面板的异步请求跟踪

总结

JavaScript 异步编程演进:

graph LR
    A[回调函数] --> B[Promise]
    B --> C[Generator]
    C --> D[async/await]
    D --> E[异步迭代器]
    E --> F[Web Workers]

掌握 JavaScript 异步编程的关键:

  1. 理解事件循环机制 - 微任务 vs 宏任务
  2. 熟练 Promise 核心概念 - 状态、链式调用、组合
  3. 合理使用 async/await - 同步风格写异步代码
  4. 掌握高级模式 - 并发控制、取消操作、进度跟踪
  5. 遵循最佳实践 - 错误处理、性能优化、代码可维护性

通过深入理解这些概念和技术,你将能够构建高效、响应迅速的 JavaScript 应用程序,轻松处理从简单到复杂的各种异步场景。

















7️⃣ 参考 7

JavaScript 异步编程是其核心特性之一,它允许代码在等待操作(如网络请求、文件 I/O)完成时继续执行,避免阻塞主线程。以下是 JavaScript 异步编程的全面解析:


一、异步编程的必要性 JavaScript 是单线程语言,浏览器中只有一个主线程负责:

  • 渲染 UI
  • 处理用户交互
  • 执行 JavaScript 代码

如果所有操作都同步执行:

const data = fetchData(); // 假设耗时 2 秒
renderUI(); // 被阻塞 2 秒
handleClick(); // 用户点击无响应

异步编程解决了这个问题,让耗时操作在后台执行,完成后通过回调通知主线程。


二、异步演进史      1. 回调函数 (Callback) 最基础的异步模式:

function fetchData(callback) {
  setTimeout(() => {
    callback('数据加载完成');
  }, 1000);
}

fetchData(result => {
  console.log(result); // 1秒后输出
});

问题:回调地狱 (Callback Hell)

getUser(id, user => {
  getPosts(user.id, posts => {
    getComments(posts[0].id, comments => {
      // 更多嵌套...
    });
  });
});

     2. Promise (ES6) 状态机管理异步操作:

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 ? 
        resolve('成功') : 
        reject('失败');
    }, 1000);
  });
}

fetchData()
  .then(console.log)
  .catch(console.error);

     3. async/await (ES2017) 用同步写法处理异步:

async function loadData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

三、核心异步机制      1. 事件循环 (Event Loop) JavaScript 的异步基石:

graph LR
A[调用栈] --> B[Web APIs]
B --> C[任务队列]
C --> D[事件循环]
D --> A
  • 调用栈:同步代码执行
  • Web APIs:处理定时器、网络请求等
  • 任务队列:存储回调(微任务/宏任务)
  • 事件循环:检查调用栈为空时执行队列任务

     2. 任务类型

类型示例优先级
微任务Promise.thenqueueMicrotask
宏任务setTimeoutsetInterval

执行顺序:同步代码 > 微任务 > 宏任务

console.log('1'); // 同步

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

Promise.resolve().then(() => {
  console.log('3'); // 微任务
});

console.log('4'); // 同步

// 输出:1 → 4 → 3 → 2

四、现代异步模式      1. Promise 组合方法

// 并行执行
Promise.all([fetchA(), fetchB()])
  .then(([a, b]) => console.log(a, b));

// 任意一个完成
Promise.race([fetchA(), fetchB()])
  .then(first => console.log(first));

// 全部完成(无论成功失败)
Promise.allSettled([fetchA(), fetchB()])
  .then(results => results.forEach(console.log));

// 任意一个成功
Promise.any([fetchA(), fetchB()])
  .then(firstSuccess => console.log(firstSuccess));

     2. 异步迭代 处理流式数据:

async function processStream() {
  const asyncIterable = createAsyncIterable();
  
  for await (const chunk of asyncIterable) {
    console.log('收到数据块:', chunk);
  }
}

     3. Web Workers 多线程并行计算:

// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ data: heavyData });
worker.onmessage = e => console.log(e.data);

// worker.js
self.onmessage = e => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

五、异步最佳实践      1. 错误处理

// 正确方式:集中捕获
async function main() {
  try {
    await operation1();
    await operation2();
  } catch (error) {
    console.error('全局捕获:', error);
  }
}

// 危险:部分错误被忽略
async function risky() {
  await operation1().catch(e => console.log(e)); // ❌ 错误1被吞
  await operation2(); // 错误2未被处理
}

     2. 性能优化

// 串行 vs 并行
async function serial() {
  const a = await fetchA(); // 等待
  const b = await fetchB(); // 等待
  return [a, b]; // 总时间 = A+B
}

async function parallel() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return [a, b]; // 总时间 = max(A,B)
}

     3. 取消异步 使用 AbortController

const controller = new AbortController();

async function fetchWithCancel() {
  try {
    const res = await fetch('/api', {
      signal: controller.signal
    });
    return res.json();
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('请求被取消');
    }
  }
}

// 取消请求
controller.abort();

六、常见异步场景      1. 网络请求

async function loadUser() {
  const response = await fetch('/api/user');
  if (!response.ok) throw new Error('请求失败');
  return response.json();
}

     2. 定时操作

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function animate() {
  await delay(1000);
  element.style.opacity = '0.5';
}

     3. 文件读取

async function readFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsText(file);
  });
}

七、调试技巧

  1. 异步堆栈追踪

    async function parent() {
      await child(); // 保留完整调用栈
    }
    
  2. console 增强

    console.time('load');
    await loadData();
    console.timeEnd('load'); // 输出执行时间
    
  3. Promise 可视化: 使用浏览器开发者工具的 Promise 调试功能


八、异步编程原则

  1. 避免阻塞主线程 - 任何超过 50ms 的操作应异步化
  2. 优先使用 async/await - 提高代码可读性
  3. 合理使用并行 - 用 Promise.all 加速独立操作
  4. 明确错误处理 - 所有异步路径都应有错误处理
  5. 考虑取消机制 - 对可能中断的操作提供取消支持

总结:JavaScript 异步工具箱

工具适用场景关键优势
回调函数简单异步操作、事件处理浏览器兼容性好
Promise链式异步操作、错误传播解决回调地狱
async/await复杂异步逻辑、同步风格代码代码可读性高
Web WorkersCPU 密集型任务多线程并行
RxJS事件流处理、高级异步组合响应式编程能力强大

掌握这些异步技术,可以构建高性能、响应迅速的 JavaScript 应用,有效处理 I/O 操作、网络请求等场景,同时保持流畅的用户体验。

















8️⃣ 参考 8

JavaScript 异步编程完全指南:从回调到 async/await

一、JavaScript 异步编程演进史

graph LR
    A[回调函数] --> B[Promise]
    B --> C[Generator]
    C --> D[async/await]
    D --> E[顶层await]

二、核心异步模式详解

     1. 回调函数(Callback)

function fetchData(callback) {
  setTimeout(() => {
    const data = { id: 1, name: '示例数据' };
    callback(null, data); // 错误优先模式
  }, 1000);
}

// 使用
fetchData((err, data) => {
  if (err) console.error(err);
  else console.log(data);
});

问题:回调地狱(Callback Hell)

getUser(userId, (err, user) => {
  if (err) return handleError(err);
  
  getPosts(user.id, (err, posts) => {
    if (err) return handleError(err);
    
    getComments(posts[0].id, (err, comments) => {
      if (err) return handleError(err);
      // 更多嵌套...
    });
  });
});

     2. Promise(承诺)

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    Math.random() > 0.5 ? 
      resolve('成功数据') : 
      reject(new Error('失败原因'));
  }, 1000);
});

// 使用
promise
  .then(data => console.log(data))
  .catch(error => console.error(error));

     3. async/await(异步/等待)

async function fetchUserData() {
  try {
    const response = await fetch('/api/user');
    const user = await response.json();
    const posts = await fetch(`/api/posts?userId=${user.id}`);
    return { user, posts };
  } catch (error) {
    console.error('请求失败:', error);
    return null;
  } finally {
    console.log('请求完成');
  }
}

三、Promise 高级用法

     1. 组合多个 Promise

方法描述示例
Promise.all()所有成功或一个失败Promise.all([p1, p2])
Promise.race()第一个解决或拒绝Promise.race([p1, p2])
Promise.allSettled()所有解决或拒绝Promise.allSettled([p1, p2])
Promise.any()第一个成功解决Promise.any([p1, p2])

     2. 超时控制实现

function timeout(promise, ms) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('超时')), ms)
    )
  ]);
}

// 使用
async function fetchWithTimeout() {
  try {
    const response = await timeout(fetch('/api/data'), 5000);
    return response.json();
  } catch (error) {
    console.error(error.message); // "超时"
  }
}

     3. 自动重试机制

async function retry(fn, maxAttempts = 3, delay = 1000) {
  try {
    return await fn();
  } catch (error) {
    if (maxAttempts <= 1) throw error;
    await new Promise(r => setTimeout(r, delay));
    return retry(fn, maxAttempts - 1, delay * 2); // 指数退避
  }
}

// 使用
async function fetchResource() {
  return retry(() => fetch('/api/unstable'), 5);
}

四、async/await 最佳实践

     1. 并行优化技巧

// 低效:顺序等待
async function slow() {
  const a = await fetchA();
  const b = await fetchB(); // 等待A完成
  return { a, b };
}

// 高效:并行执行
async function fast() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return { a, b };
}

     2. 循环中的异步处理

// 顺序执行
async function processSequentially(items) {
  for (const item of items) {
    await processItem(item);
  }
}

// 并行执行
async function processInParallel(items) {
  await Promise.all(items.map(item => processItem(item)));
}

// 控制并发数
async function processWithConcurrency(items, concurrency = 5) {
  const results = [];
  
  for (let i = 0; i < items.length; i += concurrency) {
    const chunk = items.slice(i, i + concurrency);
    const chunkResults = await Promise.all(chunk.map(processItem));
    results.push(...chunkResults);
  }
  
  return results;
}

     3. 错误处理模式

// 方式1:try/catch
async function fetchData() {
  try {
    const data = await fetch('/api');
    return process(data);
  } catch (error) {
    console.error(error);
    return fallback();
  }
}

// 方式2:catch方法
async function loadResource() {
  const data = await fetch('/api')
    .catch(error => {
      console.warn('使用缓存数据:', error);
      return getCachedData();
    });
  
  return process(data);
}

// 方式3:错误包装
async function safeFetch() {
  const [error, data] = await fetch('/api')
    .then(data => [null, data])
    .catch(error => [error, null]);
  
  if (error) return fallback();
  return data;
}

五、现代异步模式

     1. 顶层 await (ES2022)

// 模块顶层直接使用await
const config = await fetchConfig();
export default initializeApp(config);

     2. Promise.withResolvers (ES2024)

// 创建可外部控制的Promise
const { promise, resolve, reject } = Promise.withResolvers();

document.getElementById('btn').addEventListener('click', () => {
  resolve('按钮被点击');
});

const result = await promise;
console.log(result); // "按钮被点击"

     3. 异步迭代器 for-await-of

async function processStream() {
  const stream = getReadableStream(); // 如Node.js流或异步生成器
  
  for await (const chunk of stream) {
    console.log('收到数据块:', chunk);
    await processChunk(chunk);
  }
}

六、常见异步场景解决方案

     1. 用户交互序列

async function userRegistration() {
  try {
    const email = await showEmailModal();
    const password = await showPasswordModal();
    const user = await createUser(email, password);
    await sendWelcomeEmail(user);
    return user;
  } catch (error) {
    if (error instanceof UserCancelError) {
      console.log('用户取消注册');
    } else {
      showError(error.message);
    }
  }
}

     2. API 请求瀑布流

async function fetchUserDashboard(userId) {
  const user = await fetchUser(userId);
  const [orders, messages] = await Promise.all([
    fetchOrders(user.lastOrderId),
    fetchMessages(user.inboxId)
  ]);
  
  const recommendations = await fetchRecommendations(user.interests);
  
  return { user, orders, messages, recommendations };
}

     3. 实时数据轮询

async function pollData(url, interval = 5000) {
  while (true) {
    try {
      const response = await fetch(url);
      const data = await response.json();
      
      if (data.status === 'ready') return data;
      if (data.status === 'failed') throw new Error('处理失败');
      
      await new Promise(r => setTimeout(r, interval));
    } catch (error) {
      console.error('轮询错误:', error);
      await new Promise(r => setTimeout(r, interval * 2)); // 错误时增加间隔
    }
  }
}

七、性能优化与陷阱规避

     1. 内存泄漏预防

async function processLargeDataset() {
  const stream = getDataStream();
  let processed = 0;
  
  for await (const chunk of stream) {
    const result = await processChunk(chunk);
    await saveResult(result);
    
    processed++;
    if (processed % 1000 === 0) {
      // 定期释放内存
      await new Promise(resolve => setTimeout(resolve, 0));
    }
  }
}

     2. 避免阻塞事件循环

// 将CPU密集型任务拆解
async function processLargeArray(array) {
  const results = [];
  const CHUNK_SIZE = 1000;
  
  for (let i = 0; i < array.length; i += CHUNK_SIZE) {
    const chunk = array.slice(i, i + CHUNK_SIZE);
    
    // 允许事件循环处理其他任务
    await new Promise(resolve => setTimeout(resolve, 0));
    
    results.push(...await processChunk(chunk));
  }
  
  return results;
}

     3. 常见陷阱解决方案

陷阱错误示例解决方案
忘记awaitsaveData(data);await saveData(data);
循环中错误处理array.forEach(async item => {...})使用for...of循环
并行意外顺序化await p1; await p2;Promise.all([p1, p2])
Promise未处理拒绝fetch('/api');添加.catch()处理
资源未释放finally使用try/finally

八、异步调试技巧

     1. 异步堆栈追踪

// 启用异步堆栈追踪
async function fetchData() {
  // 在错误对象中保留原始堆栈
  const error = new Error('原始错误');
  Error.captureStackTrace(error, fetchData);
  
  await new Promise(r => setTimeout(r, 100));
  throw error;
}

// 使用
fetchData().catch(err => console.log(err.stack));

     2. 使用async_hooks (Node.js)

const async_hooks = require('async_hooks');

// 创建异步上下文跟踪
const ctx = new Map();

const hook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    ctx.set(asyncId, { type, triggerAsyncId });
  },
  destroy(asyncId) {
    ctx.delete(asyncId);
  }
});

hook.enable();

// 调试异步操作
async function main() {
  await fetchData();
  // 查看当前异步上下文
  console.log(ctx.get(async_hooks.executionAsyncId()));
}

九、总结:JavaScript 异步编程全景

     1. 技术选型指南

场景推荐方案
简单异步操作Promise.then/catch
复杂异步流程async/await
并行独立请求Promise.all
实时数据流异步迭代器 for-await-of
浏览器事件Promise + 事件监听
Node.js 流处理pipeline + 异步迭代

     2. 最佳实践清单

  1. 优先使用 async/await 提高可读性
  2. 并行独立操作 使用 Promise.all
  3. 始终处理错误 使用 try/catch 或 .catch()
  4. 清理资源 使用 finally 块
  5. 避免阻塞事件循环 拆分CPU密集型任务
  6. 使用现代语法 如顶层 await 和 Promise 组合方法
  7. 监控未处理拒绝 添加全局处理器:
    process.on('unhandledRejection', (reason) => {
      console.error('未处理的Promise拒绝:', reason);
    });
    

     3. 未来趋势

  • Web Workers:将CPU密集型任务分流到后台线程
  • WebAssembly:高性能计算与JavaScript互操作
  • Reactive Programming:RxJS等库处理复杂异步事件流
  • 并发原语:如SharedArrayBuffer和Atomics API
graph TD
    A[异步问题] --> B{解决方案}
    B --> C[回调函数]
    B --> D[Promise]
    B --> E[async/await]
    B --> F[响应式编程]
    C --> G[回调地狱]
    D --> H[链式调用]
    E --> I[同步风格]
    F --> J[事件流处理]
    H --> K[可读性提升]
    I --> K
    J --> K
    K --> L[可维护应用]

掌握JavaScript异步编程是现代Web开发的必备技能。从基础的回调函数到现代的async/await,理解每种模式的适用场景和最佳实践,能够帮助你构建高性能、可维护的应用程序。随着ECMAScript标准的不断发展,JavaScript的异步处理能力也将继续增强。

















9️⃣ 参考 9

JavaScript 异步编程全面指南

JavaScript 是单线程语言,异步编程是其核心特性之一,用于处理非阻塞操作。下面我将全面解析 JavaScript 的异步编程模型,涵盖从基础到高级的所有概念。

异步编程的核心概念

     1. 事件循环(Event Loop) JavaScript 的异步机制基于事件循环:

console.log('开始'); // 同步任务

setTimeout(() => {
  console.log('定时器回调'); // 宏任务
}, 0);

Promise.resolve().then(() => {
  console.log('Promise 回调'); // 微任务
});

console.log('结束'); // 同步任务

// 输出顺序:
// 开始
// 结束
// Promise 回调
// 定时器回调

     2. 回调函数(Callbacks) 最早的异步处理方式:

function fetchData(callback) {
  setTimeout(() => {
    callback('数据加载完成');
  }, 1000);
}

fetchData((result) => {
  console.log(result);
});

Promise 核心机制

     1. Promise 基础

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    Math.random() > 0.5 ? 
      resolve('成功!') : 
      reject(new Error('失败!'));
  }, 1000);
});

     2. Promise 方法链

promise
  .then(result => {
    console.log(result);
    return result.toUpperCase();
  })
  .then(uppercaseResult => {
    console.log(uppercaseResult);
  })
  .catch(error => {
    console.error('错误:', error.message);
  })
  .finally(() => {
    console.log('操作完成');
  });

     3. Promise 静态方法

// 并行处理多个Promise
Promise.all([
  fetch('/api/user'),
  fetch('/api/posts')
])
  .then(([user, posts]) => {
    console.log('用户:', user);
    console.log('文章:', posts);
  })
  .catch(error => {
    console.error('有一个请求失败', error);
  });

// 其他实用方法:
Promise.race([p1, p2]); // 最先完成的Promise
Promise.allSettled([p1, p2]); // 所有Promise完成(无论成功失败)
Promise.any([p1, p2]); // 第一个成功的Promise

Async/Await 现代异步处理

     1. 基本用法

async function fetchUserData() {
  try {
    const response = await fetch('https://api.example.com/user');
    const data = await response.json();
    
    // 并行处理
    const [orders, messages] = await Promise.all([
      fetchOrders(data.id),
      fetchMessages(data.id)
    ]);
    
    return { user: data, orders, messages };
  } catch (error) {
    console.error('数据获取失败:', error);
    throw error; // 重新抛出错误
  } finally {
    console.log('请求结束');
  }
}

     2. 高级模式 错误优先处理:

async function safeFetch(url) {
  try {
    const response = await fetch(url);
    return [null, await response.json()];
  } catch (error) {
    return [error, null];
  }
}

// 使用
const [err, data] = await safeFetch('/api/data');

异步迭代:

async function processItems(items) {
  // 顺序处理
  for (const item of items) {
    await processItem(item);
  }
  
  // 并行处理(限制并发数)
  const concurrencyLimit = 5;
  for (let i = 0; i < items.length; i += concurrencyLimit) {
    const batch = items.slice(i, i + concurrencyLimit);
    await Promise.all(batch.map(processItem));
  }
}

性能优化策略

     1. 并行与顺序执行

// 错误:顺序执行(慢)
async function sequentialRequests() {
  const user = await fetch('/user');
  const posts = await fetch(`/posts/${user.id}`);
  return posts;
}

// 正确:并行执行(快)
async function parallelRequests() {
  const [user, posts] = await Promise.all([
    fetch('/user'),
    fetch('/posts') // 如果不需要user.id
  ]);
  return { user, posts };
}

     2. 取消异步操作

const controller = new AbortController();

async function fetchWithCancel(url) {
  try {
    const response = await fetch(url, {
      signal: controller.signal
    });
    return await response.json();
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('请求被取消');
    } else {
      throw error;
    }
  }
}

// 取消请求
controller.abort();

异步编程最佳实践

  1. 优先使用 async/await:提高代码可读性
  2. 始终处理错误:避免未捕获的 Promise 拒绝
  3. 避免过度嵌套:使用 Promise.all 或异步循环
  4. 注意内存泄漏:清理事件监听器和引用
  5. 使用异步队列:控制高并发场景
  6. 考虑使用 RxJS:复杂异步场景的响应式编程
  7. 监控异步性能:使用 Chrome DevTools 的 Async Stack Traces

现代异步模式

     1. 顶层 await (ES2022) 在模块顶层直接使用 await:

// 模块文件
const data = await fetchData();
export default data;

     2. Promise 组合

function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('超时')), timeout)
    )
  ]);
}

// 使用
try {
  const result = await withTimeout(fetch('/api'), 5000);
} catch (error) {
  console.error(error.message); // "超时" 或 API 错误
}

总结

JavaScript 异步编程已从回调地狱演进到现代的 async/await 模式。关键要点:

  • 理解事件循环:微任务 vs 宏任务
  • 掌握 Promise:基础、链式调用和静态方法
  • 善用 async/await:编写同步风格的异步代码
  • 优化性能:并行处理、取消机制
  • 错误处理:try/catch 和 Promise.catch
graph TD
    A[同步代码] --> B{异步操作}
    B -->|成功| C[Promise.then / await]
    B -->|失败| D[Promise.catch / try-catch]
    C --> E[继续执行]
    D --> E
    E --> F[结束]

通过合理运用这些异步技术,您可以构建高性能、可维护的 JavaScript 应用程序。

















🔟 参考 10

JavaScript 异步编程完全指南

     核心机制:事件循环 (Event Loop) JavaScript 是单线程语言,异步行为通过事件循环实现:

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

Promise.resolve().then(() => console.log("Promise"));

console.log("End");

/* 输出顺序:
Start
End
Promise
Timeout
*/

执行顺序

  1. 同步代码(宏任务)
  2. 所有微任务(Promise.then, queueMicrotask)
  3. 一个宏任务(setTimeout, setInterval, I/O)
  4. 重复步骤2-3

     异步解决方案演进

         1. 回调函数 (Callback)

function fetchData(callback) {
  setTimeout(() => {
    callback('Data received');
  }, 1000);
}

fetchData(data => console.log(data));

问题:回调地狱 (Callback Hell)

getUser(id, user => {
  getPosts(user, posts => {
    getComments(posts[0], comments => {
      // 嵌套层级过深...
    });
  });
});

         2. Promise (ES6)

const fetchData = () => new Promise((resolve, reject) => {
  setTimeout(() => {
    Math.random() > 0.5 ? 
      resolve('Success') : 
      reject('Error');
  }, 1000);
});

fetchData()
  .then(data => console.log(data))
  .catch(err => console.error(err))
  .finally(() => console.log('Cleanup'));

         3. async/await (ES2017)

async function loadData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (err) {
    console.error(err);
  } finally {
    console.log('Cleanup');
  }
}

     Promise 核心方法

方法描述示例
Promise.resolve()创建成功PromisePromise.resolve(42)
Promise.reject()创建失败PromisePromise.reject('error')
Promise.all()所有成功才算成功Promise.all([p1, p2])
Promise.any()任意成功即成功Promise.any([p1, p2])
Promise.race()第一个完成的结果Promise.race([p1, p2])
Promise.allSettled()所有完成(无论成败)Promise.allSettled([p1, p2])

     高级异步模式

         1. 取消异步操作 (AbortController)

const controller = new AbortController();

fetch(url, { signal: controller.signal })
  .then(response => response.json())
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('Request aborted');
    }
  });

// 取消请求
controller.abort();

         2. 异步迭代 (for-await-of)

async function processStream(stream) {
  for await (const chunk of stream) {
    console.log('Received chunk:', chunk);
  }
}

         3. 顶级 await (ES2022)

// 模块顶层使用
const data = await fetchData();
export default data;

         4. 异步队列控制

class AsyncQueue {
  constructor() {
    this.queue = [];
    this.processing = false;
  }

  async enqueue(task) {
    this.queue.push(task);
    if (!this.processing) await this.process();
  }

  async process() {
    this.processing = true;
    while (this.queue.length > 0) {
      const task = this.queue.shift();
      await task();
    }
    this.processing = false;
  }
}

     性能优化技巧

  1. 并行异步操作
// 顺序执行 (慢)
const results = [];
for (const url of urls) {
  results.push(await fetch(url));
}

// 并行执行 (快)
const promises = urls.map(url => fetch(url));
const results = await Promise.all(promises);
  1. 限制并发数
async function parallelWithLimit(tasks, limit) {
  const results = [];
  const executing = new Set();
  
  for (const task of tasks) {
    const p = task();
    executing.add(p);
    p.then(() => executing.delete(p));
    
    if (executing.size >= limit) {
      await Promise.race(executing);
    }
  }
  
  return Promise.allSettled(results);
}
  1. 缓存异步结果
function createAsyncCache(fn) {
  const cache = new Map();
  return async (key) => {
    if (cache.has(key)) return cache.get(key);
    const result = await fn(key);
    cache.set(key, result);
    return result;
  };
}

     常见异步场景解决方案

         1. 超时处理

async function fetchWithTimeout(url, timeout) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(timeoutId);
    return response.json();
  } catch (err) {
    throw new Error(`Request timed out after ${timeout}ms`);
  }
}

         2. 重试机制

async function retry(fn, retries = 3, delay = 1000) {
  try {
    return await fn();
  } catch (err) {
    if (retries <= 0) throw err;
    await new Promise(r => setTimeout(r, delay));
    return retry(fn, retries - 1, delay * 2); // 指数退避
  }
}

         3. 批量处理

async function batchProcess(items, processFn, batchSize = 10) {
  const results = [];
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    const batchResults = await Promise.allSettled(
      batch.map(item => processFn(item))
    );
    results.push(...batchResults);
  }
  return results;
}

     异步调试技巧

  1. 异步堆栈追踪
// 启用 V8 异步堆栈追踪
// Chrome DevTools -> Settings -> Experiments -> 勾选 "Async stack traces"
  1. console 异步标记
console.time('API Call');
const data = await fetchData();
console.timeEnd('API Call'); // 输出执行时间
  1. Promise 可视化: 使用浏览器 Performance 面板记录 Promise 创建和解决时间

     现代异步 API 整合

API描述异步处理
Fetch API网络请求await fetch()
File System文件系统 (Node.js)fs.promises.readFile()
Web Workers多线程worker.postMessage() + onmessage
WebSockets实时通信socket.onmessage
IndexedDB客户端数据库db.transaction()
// Fetch + async/await 示例
async function getData() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('Network response was not ok');
    return await response.json();
  } catch (error) {
    console.error('Fetch error:', error);
    throw error;
  }
}

     最佳实践

  1. 避免混合使用 then/catch 和 async/await
  2. 始终处理 Promise 拒绝(使用 catch 或 try/catch)
  3. 合理使用 Promise 组合方法(all/any/race)
  4. 异步代码性能监控(特别是循环中的 await)
  5. 优先使用原生异步 API(而非回调版本)
  6. 复杂异步流程使用状态机管理
  7. 浏览器环境考虑兼容性(async/await 需要 ES2017+)

JavaScript 异步编程已从回调地狱演进到现代的 async/await 模式。理解事件循环机制、掌握 Promise 核心方法、合理运用 async/await 语法,配合现代异步 API,可以编写出高效可维护的异步代码。

















🤔 参考 11

JavaScript 异步编程全面解析

JavaScript 的异步编程是其核心特性之一,允许执行长时间操作而不阻塞主线程。以下是完整的异步编程知识体系:

异步编程演进史

  1. 回调函数 (Callback):最基础的异步模式
  2. Promise (ES6):更结构化的异步处理
  3. async/await (ES2017):使异步代码像同步代码
  4. 异步迭代器 (ES2018)for-await-of 循环

一、回调函数(Callback) 最原始的异步处理方式,但容易导致"回调地狱"

function fetchData(callback) {
  setTimeout(() => {
    callback('数据加载完成');
  }, 1000);
}

fetchData((result) => {
  console.log(result);
});

问题:嵌套回调导致代码难以维护(回调地狱)

getUser(id, (user) => {
  getProfile(user, (profile) => {
    getPosts(profile, (posts) => {
      // 更多嵌套...
    });
  });
});

二、Promise(ES6 核心解决方案)      基本结构

const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (success) {
    resolve(value); // 成功状态
  } else {
    reject(error); // 失败状态
  }
});

     Promise 链式操作

fetch('/api/data')
  .then(response => response.json())
  .then(data => processData(data))
  .then(result => {
    console.log('处理结果:', result);
  })
  .catch(error => {
    console.error('处理失败:', error);
  })
  .finally(() => {
    console.log('请求结束');
  });

     静态方法

方法描述
Promise.all()所有成功时返回结果数组
Promise.any()任意一个成功即返回
Promise.race()第一个完成(无论成功失败)
Promise.allSettled()所有完成后返回结果状态

三、async/await(ES2017 语法糖) 使异步代码具有同步代码的可读性

     基本用法

async function fetchUserData() {
  try {
    const response = await fetch('/api/user');
    const user = await response.json();
    
    const postsResponse = await fetch(`/api/posts/${user.id}`);
    const posts = await postsResponse.json();
    
    return { user, posts };
  } catch (error) {
    console.error('数据获取失败:', error);
    throw error; // 向上传播错误
  } finally {
    console.log('请求完成');
  }
}

     关键特性

  1. async 函数总是返回 Promise
  2. await 只能在 async 函数中使用
  3. 错误处理使用 try/catch 结构
  4. 可结合 Promise 方法 实现复杂控制流

四、现代异步模式

     1. 顶级 await (ES2022) 在模块顶层直接使用 await:

// 模块中直接使用
const data = await fetchData();
console.log(data);

     2. 异步迭代器 处理异步数据流:

async function processStream(stream) {
  for await (const chunk of stream) {
    console.log('接收到数据块:', chunk);
    // 处理每个数据块
  }
}

     3. Promise 组合模式

// 超时控制
async function fetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, { signal: controller.signal });
    clearTimeout(timeoutId);
    return response.json();
  } catch (error) {
    clearTimeout(timeoutId);
    throw new Error(`请求超时: ${timeout}ms`);
  }
}

五、事件循环机制 理解异步的核心 - Event Loop 工作原理

graph LR
    A[调用栈] --> B{栈空?}
    B -->|是| C[任务队列]
    C --> D[取第一个任务]
    D --> E[执行任务]
    E --> A
    B -->|否| F[继续执行]
  1. 调用栈 (Call Stack):同步代码执行位置
  2. 任务队列 (Task Queue):宏任务队列(setTimeout、I/O)
  3. 微任务队列 (Microtask Queue):Promise、MutationObserver

执行顺序

  1. 执行同步代码
  2. 执行所有微任务
  3. 执行一个宏任务
  4. 重复步骤2-3

六、异步编程最佳实践

  1. 避免回调地狱:使用 Promise 或 async/await 扁平化代码
  2. 错误处理:始终捕获可能的异常
  3. 并行优化:使用 Promise.all() 处理独立异步操作
  4. 资源清理:使用 finallytry/finally 确保资源释放
  5. 取消机制:使用 AbortController 实现可取消操作
  6. 节流控制:限制并发请求数量
    async function throttleRequests(urls, maxConcurrent = 5) {
      const results = [];
      
      for (let i = 0; i < urls.length; i += maxConcurrent) {
        const batch = urls.slice(i, i + maxConcurrent);
        const batchResults = await Promise.all(batch.map(url => fetch(url)));
        results.push(...batchResults);
      }
      
      return results;
    }
    

七、常见异步场景解决方案

场景解决方案
顺序执行async/await 顺序调用
并行执行Promise.all()
首个成功Promise.any()
超时控制AbortController + setTimeout
重试机制递归+指数退避
流式处理异步迭代器

八、性能优化技巧

  1. 减少微任务数量:避免不必要的 Promise 封装
  2. 批量处理:合并多个异步操作
  3. 延迟执行:使用 requestIdleCallback 处理非关键任务
  4. Web Workers:将CPU密集型任务移出主线程
  5. 内存管理:及时取消不再需要的异步操作

浏览器支持与兼容性

特性支持版本
PromiseChrome 32+, Firefox 29+, Safari 8+
async/awaitChrome 55+, Firefox 52+, Safari 10.1+
顶级 awaitChrome 89+, Firefox 89+, Safari 15+
Node.js全部特性从 v14+ 开始稳定支持

总结:异步编程选择指南

graph TD
    A[简单异步] --> B(回调函数)
    C[链式操作] --> D(Promise)
    E[复杂逻辑] --> F(async/await)
    G[流处理] --> H(异步迭代器)
    I[并行任务] --> J(Promise.all)
    
    B --> D
    D --> F
    F --> H
    F --> J

掌握 JavaScript 异步编程是现代前端和后端开发的必备技能。从回调函数到 async/await 的演进,不仅改善了代码可读性和可维护性,还提供了更强大的异步控制能力。根据具体场景选择合适的异步模式,结合性能优化技巧,可以构建高效可靠的 JavaScript 应用。

















🤔 参考 12

JavaScript 异步编程全面解析

一、JavaScript 异步编程的核心概念

     1. 单线程与事件循环

  • 单线程模型:JS 只有一个主线程执行代码
  • 事件循环机制:协调主线程、消息队列和微任务队列
  • 阻塞问题:同步操作会阻塞整个线程执行

     2. 异步编程演进史

graph LR
A[回调函数] --> B[Promise]
B --> C[Generator]
C --> D[Async/Await]

二、异步解决方案详解

     1. 回调函数(Callback)

function fetchData(callback) {
  setTimeout(() => {
    callback('数据加载完成');
  }, 1000);
}

fetchData(result => console.log(result));

问题

  • 回调地狱(Callback Hell)
  • 错误处理困难
  • 流程控制复杂

     2. Promise

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    Math.random() > 0.5 
      ? resolve('成功') 
      : reject('失败');
  }, 1000);
});

promise
  .then(handleSuccess)
  .catch(handleError)
  .finally(cleanup);

         Promise 状态图:

stateDiagram-v2
    [*] --> Pending
    Pending --> Fulfilled: resolve()
    Pending --> Rejected: reject()
    Fulfilled --> [*]
    Rejected --> [*]

     3. Async/Await

async function fetchUserData() {
  try {
    const response = await fetch('/api/user');
    const data = await response.json();
    return processData(data);
  } catch (error) {
    console.error('获取数据失败:', error);
    return null;
  } finally {
    console.log('请求完成');
  }
}

三、现代异步编程最佳实践

     1. 错误处理策略

// 统一错误处理中间件
async function errorHandler(fn) {
  try {
    return await fn();
  } catch (error) {
    logError(error);
    return fallbackValue;
  }
}

// 使用
const data = await errorHandler(() => fetchData());

     2. 并发控制模式

// 自定义并发控制器
function createConcurrencyPool(max) {
  const queue = [];
  let active = 0;

  const next = () => {
    if (active < max && queue.length) {
      const { task, resolve, reject } = queue.shift();
      active++;
      
      task()
        .then(resolve)
        .catch(reject)
        .finally(() => {
          active--;
          next();
        });
    }
  };

  return task => new Promise((resolve, reject) => {
    queue.push({ task, resolve, reject });
    next();
  });
}

// 使用示例
const limitedFetch = createConcurrencyPool(3);
const results = await Promise.all(urls.map(url => 
  limitedFetch(() => fetch(url))
);

     3. 取消机制实现

function createCancellablePromise(executor) {
  let rejectFn;
  const cancelToken = new Promise((_, reject) => {
    rejectFn = reject;
  });

  const promise = new Promise(executor);
  
  return {
    promise: Promise.race([promise, cancelToken]),
    cancel: reason => rejectFn(new CancelledError(reason))
  };
}

// 使用
const { promise, cancel } = createCancellablePromise(resolve => {
  setTimeout(() => resolve('完成'), 5000);
});

// 用户取消
cancelButton.onclick = () => cancel('用户取消');

四、高级异步模式

     1. 异步迭代器(Async Iterators)

async function* asyncGenerator() {
  let i = 0;
  while (i < 5) {
    await sleep(1000);
    yield i++;
  }
}

(async () => {
  for await (const num of asyncGenerator()) {
    console.log(num);
  }
})();

     2. 响应式编程(ReactiveX)

import { fromEvent } from 'rxjs';
import { throttleTime, map } from 'rxjs/operators';

fromEvent(document, 'mousemove')
  .pipe(
    throttleTime(100),
    map(event => ({ x: event.clientX, y: event.clientY }))
  )
  .subscribe(pos => {
    console.log('鼠标位置:', pos);
  });

     3. Web Workers 多线程

// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ cmd: 'start', data: 1000000 });

worker.onmessage = e => {
  console.log('计算结果:', e.data);
};

// worker.js
self.onmessage = e => {
  if (e.data.cmd === 'start') {
    const result = heavyCalculation(e.data.data);
    self.postMessage(result);
  }
};

function heavyCalculation(n) {
  // 复杂计算
  return n * 2;
}

五、性能优化策略

     1. 异步操作优化矩阵

操作类型推荐方案示例
顺序执行Async/Awaitawait step1(); await step2()
并行独立Promise.allPromise.all([task1(), task2()])
竞速操作Promise.racePromise.race([fetch, timeout])
批量处理分页并发batchProcess(items, 100)
流处理异步迭代器for await (const item of stream)

     2. 内存管理技巧

// 避免内存泄漏
function setupEventListeners() {
  const data = getLargeData();
  
  element.addEventListener('click', () => {
    // 使用 data
  });
  
  // 清理函数
  return () => {
    element.removeEventListener('click');
    data.releaseResources();
  };
}

// 使用
const cleanup = setupEventListeners();
// 组件卸载时
cleanup();

六、错误监控与调试

     1. 全局错误捕获

// 浏览器环境
window.addEventListener('error', handleGlobalError);
window.addEventListener('unhandledrejection', handlePromiseRejection);

// Node.js 环境
process.on('uncaughtException', handleGlobalError);
process.on('unhandledRejection', handlePromiseRejection);

     2. 异步堆栈追踪

// 启用异步堆栈追踪
Error.stackTraceLimit = 50;

// 自定义异步操作标识
async function fetchData() {
  const stack = new Error().stack;
  try {
    return await actualFetch();
  } catch (err) {
    err.asyncStack = stack;
    throw err;
  }
}

七、现代浏览器异步API

     1. 网络请求

// Fetch API
const controller = new AbortController();

fetch('/api/data', {
  signal: controller.signal,
  cache: 'no-cache',
  priority: 'high'
})
  .then(processResponse)
  .catch(handleError);

// 取消请求
controller.abort();

     2. 后台任务

// 使用 requestIdleCallback
requestIdleCallback(deadline => {
  while (deadline.timeRemaining() > 0) {
    performBackgroundTask();
  }
}, { timeout: 2000 });

     3. 动画与渲染

// 使用 requestAnimationFrame
function animate() {
  // 更新动画状态
  updateAnimation();
  
  // 继续下一帧
  requestAnimationFrame(animate);
}

animate();

八、Node.js 异步特性

     1. EventEmitter 模式

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', (data) => {
  console.log('事件触发:', data);
});

myEmitter.emit('event', { value: 42 });

     2. 流处理(Streams)

const fs = require('fs');

const readStream = fs.createReadStream('input.txt');
const writeStream = fs.createWriteStream('output.txt');

readStream
  .pipe(transformStream) // 转换流
  .pipe(writeStream)
  .on('finish', () => console.log('处理完成'))
  .on('error', handleError);

     3. 集群模式(Cluster)

const cluster = require('cluster');
const os = require('os');

if (cluster.isPrimary) {
  // 主进程
  const cpus = os.cpus().length;
  
  for (let i = 0; i < cpus; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker) => {
    console.log(`Worker ${worker.id} 退出`);
    cluster.fork(); // 重启工作进程
  });
} else {
  // 工作进程
  require('./server.js');
}

九、未来发展趋势

     1. WebAssembly 异步交互

// 异步加载 WebAssembly
WebAssembly.instantiateStreaming(fetch('module.wasm'), imports)
  .then(({ instance }) => {
    const result = instance.exports.compute(1000);
    console.log('WASM 计算结果:', result);
  });

     2. 三方库演进

  • RxJS:响应式异步编程
  • Bluebird:增强 Promise 功能
  • Async.js:传统回调模式管理
  • Redux-Saga:管理应用副作用

十、总结:异步编程工具箱

场景推荐方案示例
简单请求Fetch + Async/Awaitawait fetch(url)
复杂流程Async/Await + try/catch多步带错误处理
并行操作Promise.all同时请求多个资源
竞速操作Promise.race请求超时处理
事件驱动EventEmitter自定义事件系统
数据流Streams/RxJS实时数据处理
计算密集型Web Workers后台计算任务
高并发连接池/集群数据库/服务器集群
graph TD
    A[异步需求] --> B{类型}
    B -->|简单请求| C[Fetch/Async]
    B -->|复杂流程| D[Async/Await]
    B -->|并行处理| E[Promise.all]
    B -->|事件驱动| F[EventEmitter]
    B -->|数据流| G[Streams/RxJS]
    B -->|CPU密集型| H[Web Workers]
    B -->|I/O密集型| I[Cluster/连接池]

掌握 JavaScript 异步编程需要理解:

  1. 事件循环机制
  2. Promise 核心原理
  3. Async/Await 工作方式
  4. 不同场景的最佳实践
  5. 性能优化与错误处理

随着 JavaScript 生态的不断发展,异步编程模式也在持续演进,但核心原则不变:高效利用单线程,避免阻塞,合理管理异步操作

















🤔 参考 13

JavaScript 异步编程深度指南

JavaScript 的异步编程模型是其核心特性之一,理解它对于构建高性能应用至关重要。下面我将全面解析 JavaScript 异步编程的各个方面。

异步编程基础

     为什么需要异步? JavaScript 是单线程语言,异步操作可以:

  • 避免阻塞主线程(UI 渲染和用户交互)
  • 提高应用性能和响应速度
  • 高效处理 I/O 密集型操作(网络请求、文件读写等)

     事件循环机制 JavaScript 的并发模型基于"事件循环":

graph LR
A[调用栈] --> B{事件循环}
B --> C[任务队列]
C --> D[微任务队列]
D --> E[渲染更新]
E --> B

执行顺序

  1. 执行同步代码(调用栈)
  2. 执行所有微任务(Promise、MutationObserver)
  3. 执行一个宏任务(setTimeout、事件回调)
  4. 重复步骤2-3

异步解决方案演进

     1. 回调函数(Callback) 最早的异步解决方案:

function fetchData(callback) {
  setTimeout(() => {
    callback('Data received');
  }, 1000);
}

fetchData(data => {
  console.log(data); // 1秒后输出
});

问题:回调地狱(Callback Hell),难以维护

getUser(userId, user => {
  getOrders(user.id, orders => {
    getProducts(orders[0].id, product => {
      // 更多嵌套...
    });
  });
});

     2. Promise(ES6) 解决回调地狱,提供链式调用:

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 
        ? resolve('Success!') 
        : reject('Error!');
    }, 1000);
  });
}

fetchData()
  .then(data => console.log(data))
  .catch(err => console.error(err))
  .finally(() => console.log('Cleanup'));

     3. async/await(ES2017) 让异步代码看起来像同步代码:

async function processData() {
  try {
    const data = await fetchData();
    const processed = await process(data);
    console.log(processed);
  } catch (error) {
    console.error('Failed:', error);
  } finally {
    console.log('Operation completed');
  }
}

关键异步 API 详解

     Promise 方法

// 并行执行,全部成功
Promise.all([promise1, promise2])
  .then(([result1, result2]) => { /*...*/ });

// 第一个完成(无论成功失败)
Promise.race([promise1, promise2])
  .then(firstResult => { /*...*/ });

// 全部完成(无论成功失败)
Promise.allSettled([promise1, promise2])
  .then(results => {
    results.forEach(result => 
      console.log(result.status) // fulfilled/rejected
    );
  });

// 第一个成功的结果
Promise.any([promise1, promise2])
  .then(firstSuccess => { /*...*/ });

     定时器函数

// 宏任务:当前任务队列执行完后执行
setTimeout(() => console.log('Timeout'), 0);

// 微任务:在当前任务结束后立即执行
queueMicrotask(() => console.log('Microtask'));

// 立即执行微任务
Promise.resolve().then(() => console.log('Promise'));

     事件循环示例

console.log('Start');

setTimeout(() => console.log('Timeout'), 0);

Promise.resolve()
  .then(() => console.log('Promise 1'))
  .then(() => console.log('Promise 2'));

queueMicrotask(() => console.log('Microtask'));

console.log('End');

/* 输出顺序:
Start
End
Promise 1
Microtask
Promise 2
Timeout
*/

高级异步模式

     1. 异步迭代器 处理异步数据流:

async function* asyncGenerator() {
  let i = 0;
  while (i < 3) {
    await new Promise(resolve => setTimeout(resolve, 100));
    yield i++;
  }
}

(async () => {
  for await (const num of asyncGenerator()) {
    console.log(num); // 0, 1, 2 (每100ms输出)
  }
})();

     2. 取消异步操作 使用 AbortController:

const controller = new AbortController();

async function fetchWithCancel(url) {
  try {
    const response = await fetch(url, {
      signal: controller.signal
    });
    return response.json();
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('Fetch aborted');
    }
  }
}

// 取消请求
controller.abort();

     3. 错误处理策略 全局错误捕获:

// 未捕获的 Promise 拒绝
window.addEventListener('unhandledrejection', event => {
  console.error('Unhandled rejection:', event.reason);
});

// async 函数错误
async function riskyOperation() {
  throw new Error('Something failed');
}

riskyOperation().catch(err => {
  console.error('Caught:', err);
});

性能优化技巧

     1. 并行 vs 顺序执行

// 顺序执行(慢)
async function sequential() {
  const res1 = await fetch('/api1');
  const res2 = await fetch('/api2');
  return [res1, res2];
}

// 并行执行(快)
async function parallel() {
  const [res1, res2] = await Promise.all([
    fetch('/api1'),
    fetch('/api2')
  ]);
  return [res1, res2];
}

     2. 限制并发数

async function concurrentMap(array, mapper, concurrency = 5) {
  const results = [];
  let index = 0;
  
  async function worker() {
    while (index < array.length) {
      const i = index++;
      results[i] = await mapper(array[i]);
    }
  }
  
  await Promise.all(Array(concurrency).fill().map(worker));
  return results;
}

// 使用
concurrentMap(urls, fetch, 3);

     3. 延迟加载与缓存

function createLazyLoader(fetcher) {
  let promise;
  
  return async () => {
    if (!promise) {
      promise = fetcher();
    }
    return promise;
  };
}

const getUser = createLazyLoader(() => fetch('/user'));

// 只会发起一次请求
getUser().then(/* ... */);
getUser().then(/* ... */);

实战应用场景

     1. 表单提交

async function handleSubmit(e) {
  e.preventDefault();
  
  const submitBtn = e.target.querySelector('button[type="submit"]');
  submitBtn.disabled = true;
  
  try {
    const formData = new FormData(e.target);
    const response = await fetch('/submit', {
      method: 'POST',
      body: formData
    });
    
    if (!response.ok) {
      throw new Error('Server error');
    }
    
    showSuccess('Form submitted!');
  } catch (error) {
    showError(error.message);
  } finally {
    submitBtn.disabled = false;
  }
}

     2. 实时数据更新

async function* streamUpdates(endpoint) {
  const response = await fetch(endpoint);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    const chunk = decoder.decode(value, { stream: true });
    const events = chunk.split('\n\n');
    
    for (const event of events) {
      if (event) yield JSON.parse(event);
    }
  }
}

// 使用
(async () => {
  for await (const update of streamUpdates('/updates')) {
    console.log('New update:', update);
  }
})();

总结与最佳实践

  1. 优先使用 async/await:提高代码可读性和可维护性
  2. 始终处理错误:使用 try/catch 或 .catch()
  3. 避免阻塞事件循环:将CPU密集型任务放入Worker
  4. 合理使用并发:并行独立操作,顺序处理依赖操作
  5. 取消不需要的操作:使用AbortController避免资源浪费
  6. 监控未处理拒绝:添加全局unhandledrejection监听器
  7. 考虑微任务优化:queueMicrotask比setTimeout(0)更高效

掌握这些异步编程技术,你将能够构建高性能、响应迅速的JavaScript应用,有效处理各种I/O操作和复杂业务逻辑。