当前位置: 首页 > news >正文

JavaScript Promise 终极指南 解决回调地狱的异步神器 99% 开发者都在用

你有没有写过这种让人头大的代码:想先获取用户信息,再拿用户的订单列表,最后查订单里的商品详情,结果嵌套了三层回调函数,代码乱得像一团毛线,改个逻辑得从头捋到尾,稍微多嵌套一层就成了 “回调地狱”?

别愁!今天给你拆透 JavaScript 里的 “异步救星”——Promise,小索奇当年第一次用它重构回调代码时,简直像解开了缠了半年的耳机线,清爽到想哭!

简单说就是,Promise 是专门管异步操作的 “容器”,它能把那些需要等的操作(比如接口请求、文件读取)包起来,让代码不用嵌套着写,而是像 “排队办事” 一样清晰。说白了,就是把 “先干 A 再干 B,B 干完再干 C” 的逻辑,从 “套娃” 变成 “流水线”。

先给你看个对比,以前用回调写的代码可能是这样的:

// 回调地狱现场

getUserInfo (userId, function (user) {

getOrderList (user.id, function (orders) {

getProductDetail (orders [0].productId, function (product) {

console.log (product); // 三层嵌套,眼睛都花了

}, function (err) {

console.error (' 查商品错了 ', err);

});

}, function (err) {

console.error (' 查订单错了 ', err);

});

}, function (err) {

console.error (' 查用户错了 ', err);

});

这代码要是再加一层操作,是不是想骂街?换成 Promise 写法,瞬间豁然开朗:

// Promise 写法

getUserInfo (userId)

.then (user => getOrderList (user.id))

.then (orders => getProductDetail (orders [0].productId))

.then (product => console.log (product))

.catch (err => console.error (' 出错了 ', err));

是不是清爽到飞起?这里的 then 方法就是 “上一步干完干这个”,catch 则是 “任何一步出错都走这”,不用每一步都写错误处理,简直是解放双手!

这背后的原因是啥呢?因为 Promise 有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败)。一旦状态变了,就再也改不了 —— 比如从 pending 变成 fulfilled,就永远是成功状态了。这就保证了异步操作的结果只会被处理一次,不会出现 “又成功又失败” 的混乱情况。

说到这儿可能有人会问:“我自己写的函数怎么改成返回 Promise 的?” 其实超简单,只要把异步操作包进 Promise 里就行:

// 把普通回调函数改成 Promise 版本

function getUserInfo (userId) {

return new Promise ((resolve, reject) => {

// 模拟接口请求

setTimeout (() => {

if (userId) {

resolve ({ id: userId, name: ' 张三 ' }); // 成功就调用 resolve

} else {

reject (new Error (' 用户 ID 不能为空 ')); // 失败就调用 reject

}

}, 1000);

});

}

看到没?resolve 就是 “告诉 Promise 干成了,把结果传出去”,reject 是 “干砸了,把错误传出去”。这样改造完,就能用 then 和 catch 链式调用了,是不是很简单?

不过 Promise 也有坑,小索奇亲测踩过好几次!比如新手容易犯的 “忘记写 catch”,结果异步操作出错了,控制台一片红却找不到原因 —— 因为 Promise 的错误不会主动抛出来,必须用 catch 捕获,或者在 then 的第二个参数里处理。

还有个更隐蔽的坑:在 Promise 里写了同步代码报错,比如这样:

new Promise ((resolve, reject) => {

console.log (a); //a 没定义,同步报错

resolve (' 成功 ');

}).catch (err => console.log (err));

这时候 catch 能抓到错误吗?答案是能!因为 Promise 会把 executor 函数(就是 new Promise 里的回调)里的同步错误自动变成 reject 状态,这点倒是很贴心,但要是不注意,也容易误以为是异步操作出了问题。

再给你说个进阶技巧:Promise.all 和 Promise.race 的用法。如果要同时请求三个接口,等全部返回再处理,就用 Promise.all:

Promise.all ([

getUserInfo (1),

getOrderList (1),

getProductDetail (101)

]).then (results => {

const user = results [0];

const orders = results [1];

const product = results [2];

// 三个结果都拿到了,开始处理

}).catch (err => {

// 只要有一个接口失败,就会进这里

});

要是想 “谁先返回就用谁”,比如同时请求两个图片接口,哪个快显示哪个,就用 Promise.race:

Promise.race ([

fetchImage ('url1'),

fetchImage ('url2')

]).then (image => {

console.log (' 显示快的图片 ', image);

});

是不是超实用?你平时处理多异步操作的时候,是用嵌套回调还是 Promise?评论区说说你第一次用 Promise 踩过的坑!

前面忘了提一句,Promise 虽然解决了回调地狱,但如果逻辑复杂,一堆 then 连起来也会有点乱,这时候就可以用 async/await 了 —— 不过那是 Promise 的 “语法糖”,本质还是基于 Promise 实现的,先把 Promise 吃透,再学 async/await 会更轻松。

我是【即兴小索奇】,点击关注,后台回复 领取,获取更多相关资源


文章转载自:

http://3V4Ahmpe.nrmyj.cn
http://RFGkHFt4.nrmyj.cn
http://56ZBxFIR.nrmyj.cn
http://VuygX5Sx.nrmyj.cn
http://tGaIsdeL.nrmyj.cn
http://qytaahP9.nrmyj.cn
http://APUrcwx2.nrmyj.cn
http://3kQd024M.nrmyj.cn
http://zAwQVZx3.nrmyj.cn
http://Tf4o5goH.nrmyj.cn
http://qyuZsCid.nrmyj.cn
http://2UxgwS0S.nrmyj.cn
http://BkGJ6JbQ.nrmyj.cn
http://3rI72TwY.nrmyj.cn
http://uH7IAENt.nrmyj.cn
http://PsT1oobr.nrmyj.cn
http://f1y5rRMz.nrmyj.cn
http://MVyYBDUG.nrmyj.cn
http://X8zidS98.nrmyj.cn
http://ueSujvkc.nrmyj.cn
http://wh8vkYN3.nrmyj.cn
http://R7hYZ17m.nrmyj.cn
http://imcDGMwW.nrmyj.cn
http://MpK9ViW5.nrmyj.cn
http://zP9CmbdE.nrmyj.cn
http://jkiXXBRA.nrmyj.cn
http://jl3nDuzu.nrmyj.cn
http://nCnw3cax.nrmyj.cn
http://LSa1UFRy.nrmyj.cn
http://EHGw5N5G.nrmyj.cn
http://www.dtcms.com/a/388600.html

相关文章:

  • AI智能体开发实战:从提示工程转向上下文工程的完整指南
  • jtag协议处理流程
  • 【LeetCode 每日一题】2749. 得到整数零需要执行的最少操作数
  • 《饿殍:明末千里行》Switch版试玩发布 3月13日发售
  • LeetCode:9.找到字符串中所有的字母异位词
  • Java获取淘宝商品详情数据的详细说明
  • PyTorch张量运算、索引与自动微分详解
  • Simulink变量优先级与管理策略
  • 大模型学习:什么是FastText工具
  • 从芯片到云:微软Azure全栈硬件安全体系构建可信基石
  • 当文件传输遇上网络波动:如何实现稳定高效的数据交换
  • C++访问限定符private、public、protected的使用场景
  • springboot 使用CompletableFuture多线程调用多个url接口,等待所有接口返回后统一处理接口返回结果
  • 科普:build与make
  • 对比OpenCV GPU与CPU图像缩放的性能与效果差异
  • 网络工程师行业新技术新概念
  • 【Linux】Linux中dos2unix 工具转换文件格式
  • 实验4:表单控件绑定(2学时)
  • QT OpenCV 准备工具
  • 无锁化编程(Lock-Free Programming)分析
  • Centons7 docker 安装 playwright
  • 远距离传输大型文件:企业数字化转型的挑战与突破
  • 氧气科技亮相GDMS全球数字营销峰会,分享AI搜索时代GEO新观
  • useMemo和useCallback
  • 【数据结构---图的原理与最小生成树算法,单源最短路径算法】
  • 有发声生物(猫狗鸟等)与无发声生物(蚂蚁蝙蝠蛇等)的 “感知-->行动“
  • CC 攻击为什么越来越难防?
  • 量化交易 - Multiple Regression 多变量线性回归(机器学习)
  • 【机器学习】基于双向LSTM的IMDb情感分析
  • CLR-GAN训练自己的数据集