一、Promise

1. 什么是 Promise?

Promise 是 JavaScript 中用于处理异步操作的对象,它代表一个异步操作的最终完成(或失败)及其结果值。

2. Promise 的三种状态
​​Pending(待定)​​:初始状态,既不是成功,也不是失败状态
​​Fulfilled(已兑现)​​:意味着操作成功完成
​​Rejected(已拒绝)​​:意味着操作失败
3. 创建 Promise
const myPromise = new Promise((resolve, reject) => {// 异步操作if (/* 操作成功 */) {resolve(value); // 将Promise状态改为fulfilled} else {reject(error);  // 将Promise状态改为rejected}
});
4. Promise 的方法

then()

myPromise.then((value) => { /* 成功时的处理 */ },(error) => { /* 失败时的处理 */ }
);

catch()

myPromise.catch((error) => { /* 失败时的处理 */ }
);

finally()

myPromise.finally(() => { /* 无论成功失败都会执行 */ }
);
5. Promise 的静态方法

Promise.resolve()

Promise.resolve(value); // 返回一个已解决的Promise

Promise.reject()

Promise.reject(reason); // 返回一个已拒绝的Promise

Promise.all()

Promise.all([promise1, promise2, ...]).then((values) => { /* 所有Promise都成功 */ }).catch((error) => { /* 任一Promise失败 */ });

Promise.race()

Promise.race([promise1, promise2, ...]).then((value) => { /* 第一个完成的Promise */ });

Promise.allSettled() (ES2020)

Promise.allSettled([promise1, promise2, ...]).then((results) => { /* 所有Promise都完成 */ });
6. Promise 链式调用
doSomething().then(result => doSomethingElse(result)).then(newResult => doThirdThing(newResult)).then(finalResult => console.log(`Got the final result: ${finalResult}`)).catch(failureCallback);

二、async/await

1. 什么是 async/await?

async/await 是建立在 Promise 之上的语法糖,让异步代码看起来更像同步代码。

2. async 函数
async function myFunction() {return "Hello";
}

// 等同于

function myFunction() {return Promise.resolve("Hello");
}
3. await 表达式
async function myFunction() {const result = await somePromise;console.log(result);
}
4. 错误处理

try/catch

async function myFunction() {try {const result = await somePromise;console.log(result);} catch (error) {console.error(error);}
}

结合 catch()

async function myFunction() {const result = await somePromise.catch(error => {console.error(error);return defaultValue;});console.log(result);
}
5. 并行执行
async function myFunction() {// 顺序执行const result1 = await promise1;const result2 = await promise2;// 并行执行const [result1, result2] = await Promise.all([promise1, promise2]);
}
6. async/await 与 Promise 的对比
// 使用Promise
function getJSON() {return fetch('/data.json').then(response => {if (response.status === 200) {return response.json();} else {throw new Error('Unable to fetch data');}}).then(data => console.log(data)).catch(err => console.log(err));
}// 使用async/await
async function getJSON() {try {const response = await fetch('/data.json');if (response.status === 200) {const data = await response.json();console.log(data);} else {throw new Error('Unable to fetch data');}} catch (err) {console.log(err);}
}

三、最佳实践

1. Promise 最佳实践
​​总是返回或终止 Promise 链​​:在 then() 中总是返回新的 Promise 或 throw 错误
​​避免 Promise 嵌套​​:使用链式调用代替嵌套
​​使用 catch() 处理错误​​:不要忽略 Promise 的错误
​​命名 Promise 函数​​:提高代码可读性
2. async/await 最佳实践
​​尽量使用 try/catch​​:正确处理错误
​​避免不必要的 await​​:可以并行执行的不要顺序执行
​​考虑顶层 await​​:在模块顶层使用 await (ES2022)
​​不要混用 then() 和 async/await​​:选择一种风格并保持一致

四、高级用法

1. Promise 取消
function cancellablePromise(executor) {let cancel;const promise = new Promise((resolve, reject) => {executor(resolve, reject);cancel = reject;});promise.cancel = cancel;return promise;
}const p = cancellablePromise((resolve, reject) => {setTimeout(() => resolve('Done'), 2000);
});p.cancel('Operation cancelled');
2. async 生成器
async function* asyncGenerator() {let i = 0;while (i < 3) {await new Promise(resolve => setTimeout(resolve, 1000));yield i++;}
}(async function() {for await (const num of asyncGenerator()) {console.log(num);}
})();
3. 顶层 await (ES2022)
// 在模块顶层直接使用await
const data = await fetch('/data.json').then(res => res.json());
console.log(data);

五、async 函数与 Promise 的关系

1. async 函数的返回值

​​不需要​​在 async 函数中显式返回 new Promise,因为 async 函数​​自动​​将返回值包装为 Promise:

async function foo() {return 42; // 自动包装为 Promise.resolve(42)
}

// 等同于

function foo() {return Promise.resolve(42);
}
2. 何时需要显式使用 new Promise

在以下情况下可能需要显式使用 new Promise:

​​包装回调式 API​​:如文件系统、网络操作、子进程、定时器、事件监听、Web API等
async function readFileAsync(path) {return new Promise((resolve, reject) => {fs.readFile(path, (err, data) => {if (err) reject(err);else resolve(data);});});
}

​​需要手动控制 resolve/reject 时机​​:

async function waitForEvent(element, eventName) {return new Promise((resolve) => {element.addEventListener(eventName, resolve, { once: true });});
}

六、async/await 与 Promise 的区别

特性Promiseasync/await
语法​​链式调用 .then().catch()类似同步代码的语法
错误处理​​使用 .catch() 或第二个参数使用 try/catch 块
​​可读性​​回调嵌套可能导致"回调地狱"线性执行,代码更清晰
调试​​调试较困难(匿名函数)调试更直观(有函数名和行号)
返回值​​总是返回 Promise总是返回 Promise
执行流程​​基于事件循环的微任务基于事件循环的微任务

七、如何配合使用 async/await 和 Promise

1. 最佳实践:混合使用场景

(1) 并行操作 + await

async function fetchAllData() {// 并行启动所有请求const [users, products, orders] = await Promise.all([fetch('/api/users'),fetch('/api/products'),fetch('/api/orders')]);// 顺序处理结果const userData = await users.json();const productData = await products.json();const orderData = await orders.json();return { userData, productData, orderData };
}

(2) 需要精细控制 Promise 时

async function withTimeout(promise, ms) {return new Promise((resolve, reject) => {const timeoutId = setTimeout(() => {reject(new Error('Operation timed out'));}, ms);promise.then(result => {clearTimeout(timeoutId);resolve(result);},error => {clearTimeout(timeoutId);reject(error);});});
}// 使用
try {const result = await withTimeout(fetch('/api/data'), 5000);
} catch (error) {console.error('Error:', error);
}
2. 错误处理模式对比

Promise 风格

function getUser(id) {return fetch(`/api/users/${id}`).then(response => {if (!response.ok) throw new Error('Not found');return response.json();}).catch(error => {console.error('Fetch failed:', error);throw error; // 继续传递错误});
}

async/await 风格

async function getUser(id) {try {const response = await fetch(`/api/users/${id}`);if (!response.ok) throw new Error('Not found');return await response.json();} catch (error) {console.error('Fetch failed:', error);throw error; // 继续传递错误}
}
3. 常见配合使用模式

(1) 异步初始化模式

let initialized = false;
let initializationPromise;async function initialize() {if (initialized) return;if (!initializationPromise) {initializationPromise = (async () => {await loadConfig();await connectToDB();initialized = true;})();}return initializationPromise;
}

// 使用
await initialize();
// 现在可以使用初始化后的资源

(2) 带缓存的异步请求

const cache = new Map();async function getWithCache(url) {if (cache.has(url)) {return cache.get(url);}const promise = fetch(url).then(response => response.json()).then(data => {cache.set(url, data);return data;});cache.set(url, promise);return promise;
}// 使用
const data = await getWithCache('/api/products');
八、性能考量
​​微任务开销​​:await 会创建额外的微任务在热代码路径中避免不必要的 await​​内存使用​​:每个 await 都会保留执行上下文长异步链可能增加内存压力​​优化技巧​​:// 次优:创建两个微任务
async function foo() {return await bar();
}
// 优化:只创建一个微任务
async function foo() {return bar();
}

九、常见问题与解决方案

1. Promise 常见问题

问题:忘记返回 Promise

// 错误
somePromise.then(value => {doSomething(value);
});// 正确
somePromise.then(value => {return doSomething(value);
});

问题:忽略错误处理

// 错误
somePromise.then(value => console.log(value));// 正确
somePromise.then(value => console.log(value)).catch(error => console.error(error));
2. async/await 常见问题

问题:忘记 await

// 错误
async function foo() {const result = someAsyncFunction(); // 忘记awaitconsole.log(result); // 输出Promise对象
}// 正确
async function foo() {const result = await someAsyncFunction();console.log(result);
}

问题:在循环中错误使用 await

// 低效 - 顺序执行
for (const url of urls) {const response = await fetch(url);console.log(await response.json());
}// 高效 - 并行执行
const promises = urls.map(url => fetch(url).then(res => res.json()));
const results = await Promise.all(promises);
results.forEach(result => console.log(result));

为什么我的 async 函数返回 undefined?

async function foo() {// 忘记 returnPromise.resolve(42);
}
const result = await foo(); // undefined​​解决方案​​:确保返回你想要的值(Promise 会自动包装)async function foo() {return Promise.resolve(42); // 显式返回// 或者直接 return 42;
}

什么时候应该使用 return await?

async function foo() {try {return await riskyOperation(); // 正确:可以捕获错误} catch (error) {return fallbackValue;}
}async function bar() {return riskyOperation(); // 错误:无法捕获错误
}

​​规则​​:

在 try/catch 块内使用 return await 以捕获错误
否则直接 return Promise 更高效(少一次微任务)

如何取消 async 函数?

function createCancellableAsyncTask(task) {let cancel;const promise = new Promise((resolve, reject) => {cancel = reject;task().then(resolve, reject);});return { promise, cancel };
}// 使用
const { promise, cancel } = createCancellableAsyncTask(async () => {await longRunningOperation();
});
// 取消
cancel(new Error('User cancelled'));

十、总结

Promise 和 async/await 都是 JavaScript 中处理异步操作的重要工具:

​​Promise​​ 提供了更结构化的异步编程方式,避免了回调地狱
​​async/await​​ 让异步代码看起来更像同步代码,提高了可读性
两者可以结合使用,async 函数总是返回 Promise,await 后面可以跟任何 thenable 对象
在实际开发中,应根据场景选择合适的方式,并遵循最佳实践

JavaScript 异步编程:async/await 与 Promise 的关系与配合使用

​​async/await 是 Promise 的语法糖​​,底层仍然是 Promise
​​不需要​​在 async 函数中显式返回 new Promise,除非:包装回调式 API需要精细控制 resolve/reject 时机
​​配合使用原则​​:使用 async/await 处理线性异步逻辑使用 Promise 方法(如 Promise.all)处理并行操作在需要精细控制或包装旧代码时使用 new Promise
​​错误处理​​:try/catch 用于 async/await.catch() 用于 Promise 链
​​性能优化​​:避免不必要的 await合理使用并行操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917108.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917108.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917108.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OS架构整理

OS架构整理引导启动部分bios bootloader区别启动流程&#xff08;x86 BIOS 启动&#xff09;&#xff1a;biosboot_loader3.切换进保护模式实模式的限制如何切换进保护模式加载kernel到内存地址1M加载内核映像文件elf一些基础知识链接脚本与代码数据段创建GDT表段页式内存管理显…

【WRF-Chem第二期】WRF-Chem有关 namelist 详解

目录namelist 选项&#xff1a;chem_opt 的选择其他化学相关的 namelist 选项气溶胶光学属性与输出边界与初始条件配置&#xff08;气体&#xff09;参考本博客详细介绍 WRF-Chem有关 namelist 选项。 namelist 选项&#xff1a;chem_opt 的选择 chem_opt 是什么&#xff1f;…

STM32-USART串口实现接收数据三种方法(1.根据\r\n标志符、2.空闲帧中断、3.根据定时器辅助接收)

本章概述思维导图&#xff1a;USART串口初始化配置串口初始化配置在&#xff08;STM32-USART串口初始化章节有详细教程配置&#xff09;&#xff0c;本章不做讲解直接代码示例&#xff0c;本章重点在于串口实现接收数据三种方法&#xff1b;配置USART1串口接收初始化函数步骤&a…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博评论数据可视化分析-点赞区间折线图实现

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解微博评论数据可视化分析-点赞区间折线图实现…

Unity_SRP Batcher

SRP Batcher 全面解析&#xff1a;原理、启用、优化与调试一、什么是 SRP Batcher&#xff1f;SRP Batcher 是 Unity Scriptable Render Pipeline&#xff08;URP、HDRP 或自定义 SRP&#xff09; 专属的 CPU 渲染性能优化技术&#xff0c;核心目标是 减少材质切换时的 CPU 开销…

详解Vite 配置中的代理功能

在前端开发过程中&#xff0c;你可能经常会遇到一个头疼的问题&#xff1a;当你在本地启动的前端项目中调用后端接口时&#xff0c;浏览器控制台会报出类似 “Access to fetch at ‘http://xxx’ from origin ‘http://localhost:3000’ has been blocked by CORS policy” 的错…

理解梯度在神经网络中的应用

梯度&#xff08;Gradient&#xff09;是微积分中的一个重要概念&#xff0c;广泛应用于机器学习和深度学习中&#xff0c;尤其是在神经网络的训练过程中。下面将从梯度的基本概念、其在神经网络中的应用两个方面进行详细介绍。一、梯度的基本概念 1.1 什么是梯度&#xff1f; …

WPF,按钮透明背景实现MouseEnter

在帮手程序&#xff08;assister.exe&#xff09;中&#xff0c;可以点击录制按钮&#xff0c;实现录制用户操作直接生成操作列表。而在弹出录制按钮的悬浮窗中&#xff0c;需要能够拖动录制按钮放置在任意的位置&#xff0c;以免阻挡正常的窗口。具体功能是&#xff0c;当鼠标…

【抄袭】思科交换机DAI(动态ARP监控)配置测试

一.概述 1.DAI作用 ①.使用DAI&#xff0c;管理员可以指定交换机的端口为信任和非信任端口&#xff1a; 信任端口可以转发任何ARP信息 非信任端口的ARP消息要进行ARP检测验证 ②.交换机执行如下的ARP验证&#xff1a; 静态ARP监控&#xff1a;为一个静态的IP地址配置一个静态AR…

在嵌入式系统或 STM32 平台中常见的外设芯片和接口

在嵌入式系统或 STM32 平台中常见的 外设芯片 或 模块名称&#xff0c;包括&#xff1a; &#x1f4fa; 显示驱动&#xff08;如 ST7735、OTM8009A、NT35510&#xff09;&#x1f4f7; 摄像头模组&#xff08;如 OV5640、OV9655、S5K5CAG&#xff09;&#x1f4be; Flash 存储器…

AI 类型的 IDE

指集成了 AI 辅助编程能力的集成开发环境 一、代码辅助生成 ✅ 自动补全&#xff08;更智能&#xff09; 比传统 IDE 更智能&#xff0c;理解上下文&#xff0c;生成整个函数/模块 示例&#xff1a;根据函数名 calculateTax 自动生成税务计算逻辑 ✅ 函数 / 类自动生成 给…

JP3-3-MyClub后台后端(一)

Java道经 - 项目 - MyClub - 后台后端&#xff08;一&#xff09; 传送门&#xff1a;JP3-1-MyClub项目简介 传送门&#xff1a;JP3-2-MyClub公共服务 传送门&#xff1a;JP3-3-MyClub后台后端&#xff08;一&#xff09; 传送门&#xff1a;JP3-3-MyClub后台后端&#xff08;…

架构实战——互联网架构模板(“存储层”技术)

目录 一、SQL 二、NoSQL 三、小文件存储 四、大文件存储 本文来源:极客时间vip课程笔记 一、SQL SQL 即我们通常所说的关系数据。前几年 NoSQL 火了一阵子,很多人都理解为 NoSQL 是完全抛弃关系数据,全部采用非关系型数据。但经过几年的试验后,大家发现关系数据不可能完全被…

CentOS7.9在线部署Dify

一、CentOS7.9安装dify 二、检查是否安装dcoker docker --version2.1下载后将安装包上传至服务器对应文件夹下,我选在放在了 /root文件夹下 cd /root2.2 上传至服务器 cd /root #对应目录下tar -xvf docker-26.1.4.tgz # 解压安装包:chmod 755 -R docker # 赋予可执…

深入浅出C语言指针:从数组到函数指针的进阶之路(中)

指针是C语言的灵魂&#xff0c;也是初学者最头疼的知识点。它像一把锋利的刀&#xff0c;用得好能大幅提升代码效率&#xff0c;用不好则会让程序漏洞百出。今天这篇文章&#xff0c;我们从数组与指针的基础关系讲起&#xff0c;一步步揭开指针进阶类型的神秘面纱&#xff0c;最…

java web Cookie处理

java web 设置cookie更改启动端口// Directory tree (5 levels) ├── src\ │ ├── a.txt │ └── com\ │ └── zhang\ │ └── ServletContext\ │ ├── cookie\ │ └── servletContext.java └── web\├─…

机器学习—线性回归

一线性回归线性回归是利用数理统计中回归分析&#xff0c;来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。相关关系&#xff1a;包含因果关系和平行关系因果关系&#xff1a;回归分析【原因引起结果&#xff0c;需要明确自变量和因变量】平行关系&#xff1…

Spring Boot Admin 监控模块笔记-实现全链路追踪

一、概述Spring Boot Admin&#xff08;SBA&#xff09;是一个用于监控和管理 Spring Boot 应用程序的工具。它提供了一个 Web 界面&#xff0c;可以集中管理多个 Spring Boot 应用程序的健康状态、指标、日志、配置等信息。通过 SBA&#xff0c;你可以轻松地监控和管理你的微服…

容器化与Docker核心原理

目录 专栏介绍 作者与平台 您将学到什么&#xff1f; 学习特色 容器化与Docker核心原理 引言&#xff1a;为什么容器化成为云计算时代的基石&#xff1f; 容器化技术全景与Docker核心原理&#xff1a;从概念到实践 文章摘要 1. 引言&#xff1a;为什么容器化成为云计算…

掌握Python三大语句:顺序、条件与循环

PS不好意思各位&#xff0c;由于最近笔者在参加全国大学生电子设计大赛&#xff0c;所以最近会出现停更的情况&#xff0c;望大家谅解&#xff0c;比赛结束后我会加大力度&#xff0c;火速讲Python的知识给大家写完&#x1f396;️&#x1f396;️&#x1f396;️&#x1f396;…