知蛛网
  • 首页
  • 会员
  • 活动
  • 工作台

常见问题
活动
关于我们
联系我们
隐私协议
用户协议
会员协议
© 2026 知蛛网. 保留所有权利。
首页会员工作台我的
flynn@flynn
主页wiki简历作品集
目录
全部书籍
00-路线
  • 学习路线
  • 命名与写作规范
01-计算机基础
01-计算机网络
  • 互联网是如何工作的
  • HTTP协议
  • TCP/IP协议
  • 浏览器直接打开本地html文件,请求时的协议问题
02-浏览器原理
  • 浏览器是如何渲染页面的
  • 浏览器是如何渲染页面的
  • 面试之浏览器
03-操作系统
  • 进程与线程
  • 内存管理与虚拟内存
  • IO 模型与多路复用
  • 文件系统与页缓存
04-数据结构与算法
  • 数组与链表
  • 栈与队列
  • 哈希表
  • 树与堆
  • 基础数据结构
01-基础数据结构
02-高级算法
  • 排序算法
  • 二分查找
  • 递归与回溯
  • 动态规划
  • 双指针与滑动窗口
03-leetcode刷题
02-前端核心
01-web开发
  • Web 和 Web 标准
  • web 入门
  • web 开发
  • URL
  • 域名
  • Web服务器
  • 命令行
  • 工作流程和流程
  • 超链接
  • 浏览器指纹
02-html
  • HTML基础语法
  • HTML 概述
  • HTML 发展史
  • HTML调试
  • HTML标题与段落
  • 文本格式化
  • 强调与重要性
  • 块级元素和内联元素
  • 列表
  • 区块
  • 语义元素
  • 页面结构化和语义化
  • 超链接
  • 相对路径和绝对路径
  • 图片
  • 表格
  • 表单和按钮
  • 多媒体
  • 视频/音频
  • HTML 头部
  • HTML 字符集
  • HTML颜色
  • HTML 语言代码
  • HTML 国家/地区
  • Emoji (表情符号)
  • HTML 标签简写及全称 |
  • SVG
  • Canvas 2D
  • Canvas 3D
  • 框架 `<iframe>`
  • HTML 拖放
  • HTML5 Geolocation(地理定位)
  • Web 存储
  • HTML URL 编码
  • MathML
  • 远程图片资源在自己网站中无法展示问题
03-css
  • CSS简介
  • CSS 语法
  • CSS 创建
  • CSS 发展史
  • CSS 浏览器支持
  • CSS 选择器
  • CSS `!important` 规则
  • css颜色
  • CSS 文本格式
  • CSS 盒子模型
  • CSS 尺寸
  • CSS 内边距
  • CSS 外边距
  • CSS 边框
  • CSS 轮廓
  • CSS 背景(background)
  • CSS 溢出
  • CSS 文档流
  • CSS 显示和可见性
  • CSS 浮动
  • CSS 定位
  • CSS 对齐方式
  • CSS 网页布局
  • CSS 多列布局(CSS Multi-column Layout)
  • CSS 透明度
  • CSS 响应式设计(Responsive Design)
  • CSS 媒体查询
  • CSS 列表
  • CSS 表格
  • CSS 表单
  • CSS 链接
  • CSS 用户界面
  • CSS 计数器
  • CSS 过渡
  • CSS 动画
  • CSS 2D 转换
  • CSS 3D 转换
  • CSS 变量(CSS Custom Properties)
  • CSS 原生嵌套(CSS Nesting)
  • CSS 函数(CSS Functions)
04-javascript
  • 什么是 JavaScript?
  • 编程范式(Programming Paradigm)
  • 什么是范式?
  • ECMAScript 规范
  • 什么是语法糖
  • 开发环境搭建
  • 什么是堆和栈?
  • 什么是执行上下文
  • JavaScript 垃圾回收机制
  • 作业队列与事件循环
  • 深拷贝和浅拷贝
  • 语法与类型
  • 字面量
  • 控制流与错误处理
  • 循环与迭代
  • 函数
  • 表达式与运算符
  • 数字和字符串
  • 表达日期与时间
  • 正则表达式
  • 索引集合类
  • 带键的集合
  • 对象
  • 类
  • Promise
  • async/await
  • 迭代器和生成器
  • 国际化
  • 模块
  • 资源管理
  • 属性的可枚举性和所有权
  • 闭包
  • 继承与原型链
  • 元编程
  • 内存管理
  • 内置对象
  • arguments 对象
  • BOM 对象(浏览器对象模型)
  • DOM 对象(文档对象模型)
  • bind、apply、call的区别
  • new 操作符
  • typeof 和 instanceof 的区别
  • HTML5 Web Workers
05-typescript
  • TypeScript 类型系统基础
  • 类型体操
03-框架与跨端
01-react
  • 开发环境搭建
  • JSX
  • 组件
  • 生命周期
  • Hooks
  • 组件通信
  • 状态管理
  • React 19 新特性
  • useCallback 闭包陷阱
  • 常用的性能优化操作
  • Firbe 架构
  • React 18 新特性
  • useRef
  • 基于umijs 4.0 搭建官网
  • react+vite本地开发,如何手机联调
  • React 实现谷歌登录
  • React 项目调起 WhatsApp
02-vue
  • vue 解决跨域请求
  • 在vue2使用TinyMCE富文本编辑器
  • 使用jszip 导出新闻
  • Vue 本地开发启用 https
  • 基于vue3+vite+ts+elementplus+pinia+axios搭建后台管理系统
03-react-native
  • iOS 开发环境(RN 0.72)
  • RN 原生模块(Native Module)
  • 查看Maven包的Java包名
  • 优化 APP 启动速度
  • 安全键盘
  • 启动图与 Icon 尺寸规范
  • RN如何生成/配置iOS的开发者证书和生产证书
  • 邓白氏编码
  • 微信开放平台配置Universal Link
  • 上架至Apple App Store
04-android
  • 开发环境搭建
  • Android项目目录结构
  • 认识Gradle
04-工程化
01-git
  • 如何解决已被git跟踪文件不在跟踪
  • git标签
  • Git报错: Failed to connect to github.com port 443 解决方案
  • Git 分支操作速查
02-构建工具
  • 构建工具原理与选型
02-webpack
  • webpack 核心概念与构建流程
  • webpack 性能优化
03-vite
  • vite 为什么快
  • vite 插件与生产构建
03-测试
  • 前端测试体系
04-部署
  • Nginx 反向代理解决跨域
  • SPA 刷新非首页报 404
05-docker
  • Docker 常用命令
  • docker-compose nginx配置ssl证书
  • Docker Desktop 升级后 docker-compose 命令找不到
06-性能优化
  • 前端性能优化体系
  • 背景 GIF 优化方案
07-微前端
  • 微前端实战(qiankun)
  • 微前端 · qiankun
01-qiankun
05-后端与数据
01-nodejs
  • Node 版本与依赖的 engines 冲突
  • Express 实现 Gmail 发信(邮箱验证码)
02-php
  • 浏览器保存新闻,发布到自有网站
  • [分布式] 浏览器保存新闻,发布到自有网站
  • 邮件发送,多账号轮询
  • nginx和php-fpm通信问题导致网站页面空白
03-python
  • macOS M1 芯片 如何安装 py 和 tkinter
  • tkinter 编写的程序如何打包成桌面软件
04-架构设计
  • 后台管理系统中角色管理、管理员管理、权限设置他们三者之间的关系
05-运维
  • redis启动失败
  • 实现自动备份宝塔项目及数据库到本地
  • 宝塔面板
01-宝塔
06-实战项目
  • 实战准备工作
02-项目记录
  • AI-Chat 模块技术文档
  • CRMChat 部署
07-面试专项
01-面试
  • 面试之自我介绍
  • CSS 面试
  • JS面试
  • React面试
  • Vue面试
  • RN 面试 · 题目清单
  • RN 面试 · 答案详解
  • RN 物流公司 · 题目清单
  • RN 物流公司 · 答案详解
  • Uniapp 面试
  • 带团队经验
12-react专项
  • 一个表格,某一行的某一列数据变动了,如何优化性能?
13-reactnative专项
  • RN 开发过程中,有遇到什么棘手的问题?你是如何解决的?
14-过往面试总结
  • 冷哥传媒 · 面试题
  • 沐腾科技 · 面试题
  • 字符频率排序
02-面试八股
  • 网络八股
  • 浏览器八股
  • 工程化八股
03-算法面试题
  • 前端高频手写题
  • 场景设计题
04-真实面试经历
  • 20251027 盾蓝科技 面试
  • 20251028 芝麻甜心 面试
08-工具
01-n8n
  • 初始n8n
  • 快速入门
  • 在宝塔中搭建n8n环境
  • n8n中常用节点
  • n8n和代码的区别
02-Trae
  • Figma MCP 配置指南
03-UI_UX_pro_max
  • UI_UX_pro_max的使用
04-开发环境
  • VMWare虚拟机安装
  • PowerShell 执行策略与编码设置
98-杂项
  • A股股票交易相关费用
99-手册
  • iOS 开发者账号申请流程及费用
  • 邓白氏编码申请及费用
  • App 推送通道申请及费用
  • App 开发收费项目清单
  • 注册AWS账号
  • 使用Amazon Polly实现文本转语音
  • Google 翻译 Key 申请与前端调用
  • 使用SmsForwarder转发短信

async/await

04-javascript2026/11/14

基本概念

  1. async 函数
  • 总是返回一个 Promise
  • 可以使用 await 关键字
  1. await 表达式
  • 只能在 async 函数内部使用
  • 暂停 async 函数的执行,等待 Promise 解决

基本用法

1. async 函数声明

// 函数声明
async function getData() {
    return "Hello async";
}

// 函数表达式
const getData = async function () {
    return "Hello async";
};

// 箭头函数
const getData = async () => {
    return "Hello async";
};

// 对象方法
const obj = {
    async fetchData() {
        return "data";
    },
};

// 类方法
class ApiClient {
    async request() {
        return "response";
    }
}

2. await 使用

async function example() {
    // 等待一个 Promise
    const result = await Promise.resolve(42);
    console.log(result); // 42

    // 等待多个独立的 Promise(顺序执行)
    const data1 = await fetchData1();
    const data2 = await fetchData2();

    // 并行执行(推荐)
    const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
}

错误处理

1. try...catch

async function fetchWithRetry(url, retries = 3) {
    for (let i = 0; i < retries; i++) {
        try {
            const response = await fetch(url);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}`);
            }
            return await response.json();
        } catch (error) {
            console.log(`Attempt ${i + 1} failed:`, error.message);
            if (i === retries - 1) throw error;
            await wait(1000 * (i + 1)); // 指数退避
        }
    }
}

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

2. 结合 .catch()

// 方法1:async 函数返回 Promise,可以用 .catch()
async function getUser() {
    const response = await fetch("/api/user");
    return response.json();
}

getUser()
    .then(user => console.log(user))
    .catch(error => console.error("Error:", error));

// 方法2:立即执行函数
(async () => {
    try {
        const user = await getUser();
        console.log(user);
    } catch (error) {
        console.error("Error:", error);
    }
})();

进阶用法

1. 并发控制

// 使用 for...of 顺序执行
async function processItems(items) {
    const results = [];
    for (const item of items) {
        const result = await processItem(item);
        results.push(result);
    }
    return results;
}

// 并行执行,控制并发数
async function parallelWithLimit(items, concurrency = 3) {
    const results = [];
    const executing = [];

    for (const item of items) {
        const p = processItem(item).then(result => {
            results.push(result);
        });
        executing.push(p);

        if (executing.length >= concurrency) {
            await Promise.race(executing);
        }
    }

    await Promise.all(executing);
    return results;
}

// 使用 async-pool 库的简化实现
async function asyncPool(poolLimit, array, iteratorFn) {
    const ret = [];
    const executing = new Set();

    for (const item of array) {
        const p = Promise.resolve().then(() => iteratorFn(item));
        ret.push(p);
        executing.add(p);

        const clean = () => executing.delete(p);
        p.then(clean).catch(clean);

        if (executing.size >= poolLimit) {
            await Promise.race(executing);
        }
    }

    return Promise.all(ret);
}
上一篇Promise
下一篇迭代器和生成器
本页目录
基本概念基本用法1. async 函数声明2. await 使用错误处理1. try...catch2. 结合 .catch()进阶用法1. 并发控制2. 取消操作3. 超时处理常见模式1. 重试模式2. 缓存模式3. 批量处理性能优化1. 避免不必要的 await2. 提前 await3. 使用 async generator调试技巧1. 调试异步调用栈2. 监控异步操作最佳实践总结

2. 取消操作

// 使用 AbortController
function createCancellableFetch() {
    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("Fetch aborted");
                return null;
            }
            throw error;
        }
    }

    function cancel() {
        controller.abort();
    }

    return { fetch: fetchWithCancel, cancel };
}

// 使用示例
const { fetch, cancel } = createCancellableFetch();

// 开始请求
const promise = fetch("https://api.example.com/data");

// 5秒后取消
setTimeout(() => cancel(), 5000);

3. 超时处理

// 为 Promise 添加超时
function withTimeout(promise, timeout) {
    let timer;
    const timeoutPromise = new Promise((_, reject) => {
        timer = setTimeout(() => {
            reject(new Error(`Timeout after ${timeout}ms`));
        }, timeout);
    });

    return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer));
}

// 使用示例
async function fetchWithTimeout(url, timeout = 5000) {
    try {
        const response = await withTimeout(fetch(url), timeout);
        return await response.json();
    } catch (error) {
        if (error.message.includes("Timeout")) {
            console.log("Request timed out");
        }
        throw error;
    }
}

常见模式

1. 重试模式

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

            console.log(`Retry ${i + 1} after ${delay}ms`);
            await new Promise(resolve => setTimeout(resolve, delay));

            // 指数退避
            delay *= 2;
        }
    }
}

// 使用示例
async function unstableApiCall() {
    const response = await fetch("https://api.example.com");
    if (Math.random() > 0.7) throw new Error("Random failure");
    return response.json();
}

// 最多重试3次
const result = await retry(unstableApiCall, 3, 1000);

2. 缓存模式

function createCachedAsync(fn, ttl = 60000) {
    // 默认缓存1分钟
    const cache = new Map();

    return async function (...args) {
        const key = JSON.stringify(args);
        const cached = cache.get(key);

        if (cached) {
            const [value, timestamp] = cached;
            if (Date.now() - timestamp < ttl) {
                console.log("Cache hit");
                return value;
            }
        }

        console.log("Cache miss");
        const result = await fn(...args);
        cache.set(key, [result, Date.now()]);
        return result;
    };
}

// 使用示例
const cachedFetch = createCachedAsync(async url => {
    const response = await fetch(url);
    return response.json();
});

// 第一次调用会实际请求
const data1 = await cachedFetch("https://api.example.com/data");

// 60秒内再次调用,返回缓存
const data2 = await cachedFetch("https://api.example.com/data");

3. 批量处理

class BatchProcessor {
    constructor(batchSize = 10, delay = 100) {
        this.batchSize = batchSize;
        this.delay = delay;
        this.queue = [];
        this.timer = null;
    }

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

            if (!this.timer) {
                this.timer = setTimeout(() => this.process(), this.delay);
            }

            if (this.queue.length >= this.batchSize) {
                clearTimeout(this.timer);
                this.process();
            }
        });
    }

    async process() {
        if (this.queue.length === 0) return;

        const batch = this.queue.splice(0, this.batchSize);
        clearTimeout(this.timer);
        this.timer = null;

        try {
            const results = await Promise.all(batch.map(item => item.task()));

            batch.forEach((item, index) => {
                item.resolve(results[index]);
            });
        } catch (error) {
            batch.forEach(item => {
                item.reject(error);
            });
        }

        // 如果还有剩余,继续处理
        if (this.queue.length > 0) {
            this.timer = setTimeout(() => this.process(), this.delay);
        }
    }
}

// 使用示例
const batchProcessor = new BatchProcessor(5, 50);

async function simulateApi(id) {
    await new Promise(resolve => setTimeout(resolve, Math.random() * 100));
    return `Result ${id}`;
}

// 添加100个任务,但会批量处理
const promises = [];
for (let i = 0; i < 100; i++) {
    promises.push(batchProcessor.add(() => simulateApi(i)));
}

const results = await Promise.all(promises);

性能优化

1. 避免不必要的 await

// ❌ 不好:顺序执行,时间更长
async function slow() {
    const user = await fetchUser();
    const posts = await fetchPosts();
    const comments = await fetchComments();
    return { user, posts, comments }; // 总时间 = t1 + t2 + t3
}

// ✅ 好:并行执行
async function fast() {
    const [user, posts, comments] = await Promise.all([fetchUser(), fetchPosts(), fetchComments()]);
    return { user, posts, comments }; // 总时间 = max(t1, t2, t3)
}

2. 提前 await

// ❌ 不好:在循环中 await
async function processAll(items) {
    const results = [];
    for (const item of items) {
        // 每次循环都等待
        const result = await processItem(item);
        results.push(result);
    }
    return results;
}

// ✅ 好:收集所有 Promise,然后一次性 await
async function processAllBetter(items) {
    const promises = items.map(item => processItem(item));
    return await Promise.all(promises);
}

// ✅ 或者分批处理
async function processInBatches(items, batchSize = 10) {
    const results = [];
    for (let i = 0; i < items.length; i += batchSize) {
        const batch = items.slice(i, i + batchSize);
        const batchPromises = batch.map(item => processItem(item));
        const batchResults = await Promise.all(batchPromises);
        results.push(...batchResults);
    }
    return results;
}

3. 使用 async generator

// 流式处理大数据集
async function* asyncGenerator(dataSource) {
    let page = 1;

    while (true) {
        const data = await fetchPage(dataSource, page);
        if (data.length === 0) break;

        for (const item of data) {
            yield item;
        }

        page++;
    }
}

// 使用 async generator
async function processLargeDataset() {
    const generator = asyncGenerator("https://api.example.com/items");

    for await (const item of generator) {
        await processItem(item);

        // 可以随时中断
        if (shouldStop()) break;
    }
}

调试技巧

1. 调试异步调用栈

// 使用 async_hooks(Node.js)
const async_hooks = require("async_hooks");

// 或使用 source-map 和错误追踪
async function debugAsync(fn) {
    const originalPrepareStackTrace = Error.prepareStackTrace;

    Error.prepareStackTrace = (error, stack) => {
        return stack.map(frame => {
            return {
                file: frame.getFileName(),
                line: frame.getLineNumber(),
                column: frame.getColumnNumber(),
                function: frame.getFunctionName(),
            };
        });
    };

    try {
        return await fn();
    } catch (error) {
        console.log("Async call stack:", error.stack);
        throw error;
    } finally {
        Error.prepareStackTrace = originalPrepareStackTrace;
    }
}

2. 监控异步操作

class AsyncMonitor {
    constructor() {
        this.active = new Map();
        this.completed = [];
    }

    track(name, promise) {
        const id = Symbol(name);
        const start = Date.now();

        this.active.set(id, { name, start });

        const cleanup = () => {
            const duration = Date.now() - start;
            this.active.delete(id);
            this.completed.push({ name, duration });

            // 只保留最近100条记录
            if (this.completed.length > 100) {
                this.completed.shift();
            }
        };

        promise.then(cleanup, cleanup);
        return promise;
    }

    getStats() {
        return {
            active: Array.from(this.active.values()),
            recent: this.completed.slice(-10),
        };
    }
}

// 使用示例
const monitor = new AsyncMonitor();

async function monitoredFetch(url) {
    return monitor.track(`fetch:${url}`, fetch(url));
}

最佳实践总结

  • 总是使用 try...catch 或 .catch() 处理错误
  • 并行执行 独立的异步操作
  • 合理控制并发,避免资源耗尽
  • 添加超时 防止无限等待
  • 考虑实现重试逻辑 处理暂时性错误
  • 避免在循环中使用 await,尽量使用 Promise.all
  • 使用 async/await 替代复杂的 Promise 链
  • 在适当的地方添加缓存 提高性能
  • 考虑使用第三方库 处理复杂场景:
    • p-limit - 并发控制
    • p-retry - 重试逻辑
    • p-timeout - 超时处理
    • p-map / p-filter - 异步数组操作
  • 注意内存泄漏:及时清理不再需要的异步操作引用