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

Promise开发【进阶】

目录

前言

Promise是什么

Promise的三种状态

pending

fulfiiled

rejected

Promise的异步操作

then()

catch()

finally()

Promise的链式调用

链式Promise状态确定

链式Promise返回值

Promise值穿透

then()方法的值穿透

catch()方法的值穿透

finally方法的值穿透

总结

Promise.race

Promise错误捕获的边界

catch只能捕获其前面的错误

catch捕获规则

其它


前言

本文对于Promise基础部分有简单解释,但更多的是尝试解释Promise的一些进阶知识

Promise是什么

PromiseJavaScript中处理异步操作的一种解决方案,它是一个对象,表示一个异步操作的最终完成或失败

Promise就像一个“承诺”:

  • 我给你一个承诺,我会在未来某个时间完成某个任务,但是什么时候完成我不能保证
  • 这个任务可能成功也可能失败
  • 通过.then()获取成功的结果
  • 通过.catch()获取失败的结果

Promise的三种状态

Promise有三种状态:

  • pending(等待中):初始状态,既不是成功,也不是失败
  • fulfiied(已成功):操作成功
  • rejected(已失败):操作失败

Promise的状态切换只有两条路径

  • pending -> fulfilled
  • pending -> rejected

Promise的状态并不会根据操作的成功与否自动切换,状态的切换由您定义

如果您想,您甚至可以让操作出错时返回一个Promise<fulfilled>状态

如果您的期望就是Promise出错,那确实是fulfilled状态

pending

当创建一个Promise后,它立马就进入“pending”状态,并且尝试执行Promise中的操作

const promise = new Promise((resolve, reject) => {
})

fulfiiled

Promise进入fulfilled状态,只需调用Promise给定的resolve()方法即可进入fulfilled状态

// pending -> fulfiiled
const promise = new Promise((resolve, reject) => {resolve();
})
console.log(promise); // Promise { undefined }

如果在promise内部重新创建一个promise2对象,让它调用自身的resolve方法,promise能成功进入fulfilled状态吗?

// pending -> fulfiiled
const promise = new Promise((resolve, reject) => {const promise2 = new Promise((resolve, reject) => {resolve("成功进入fufilled状态");})console.log("promise2:",promise2);
})
console.log("promise:",promise);

结果

promise2成功进入fulfiiled状态,但是promise仍然卡在pending状态,这说明promise的状态只受自身resolve()的控制

rejected

Promise进入reject状态,只需调用Promise给定的reject()方法即可进入rejected状态

// pending -> rejected
const promise = new Promise((resolve, reject) => {reject("进入rejected状态");
})
console.log(promise);

同样,如果在promise内部创建一个promise2对象,让它执行自身的reject(),对于promise是无影响的

Promise的异步操作

Promisefulfiiled状态rejected状态都是可以被捕获的,使用then()catch(),不过这两个方法都是“微任务”,而Promise里的代码(执行器)属于同步代码,所以在使用时要注意调用时机

(不了解微任务是什么?欢迎参考我的文章:Vue中nextTick()的理解_vue nexttick-CSDN博客)

then()

then()方法用来捕获promise对象的fulfilled状态

语法:

// pending -> fulfilled
new Promise((resolve, reject) => resolve("进入fulfilled状态")).then(value => {console.log(value);},error => {console.log(error);})
  • value => {}:value是resolve(param)里的param,用于捕获fulfilled状态
  • error => {}:error只捕获当前Promise的rejected状态,使用较少

catch()

catch()方法用来捕获promise对象的rejected状态

语法:

// pending -> rejected
const promise = new Promise((resolve, reject) => {reject("失败了");
}).catch((error) => {console.log(error);
})
  • error:接收reject()传递的错误参数

finally()

finally()方法不管Promise状态是fulfilled或rejected状态,都会执行,它不接接收参数,finally是微任务

const promise = new Promise((resolve, reject) => {resolve('成功');
}).then((value) => {console.log(value);throw new Error('失败');
}).catch((error) => {console.log(error);
})

效果:

Promise的链式调用

Promise的三种回调:“then()”、“catch()”、“finally()”都会返回一个新的Promise对象,这意味着我们可以无限嵌套调用三种回调方法,也就是传统意义上的链式调用。这也意味着,如果你想,你可以任意搭配三种回调的顺序你甚至可以写出反人类的代码

// then -> catch -> finally(推荐顺序)
const promise = new Promise((resolve, reject) => {resolve("成功!");
}).then((value) => {console.log(value);return value + "then";
}).catch((error) => {console.log(error);return error + "catch";
}).finally(() => {console.log("finally")
})
// finally -> then -> catch(反人类代码片段1)
const promise2 = new Promise((resolve, reject) => {reject("错误!");
}).finally(() => {console.log("finally");return "finally";
}).then((value) => {console.log(value);return value + "then";
}).catch((error) => {console.log(error);return error + "catch";
})
// then -> finally -> catch(反人类代码片段2)
const promise3 = new Promise((resolve, reject) => {reject("错误!");
}).then((value) => {console.log(value);return "then";
}).finally((value) => {console.log(value);return "finally";
}).catch((error) => {console.log(error);return error + "catch";
})

注意:

  • 因为finally不能接收参数,所以finally在链式调用中不宜放在中间位置,因为这会导致finally之前的Promise传递的参数无法正确传递给finally之后的Promise
  • catch会捕捉该位置之前的所有回调的错误

链式Promise状态确定

因为then()、catch()、finally()都会返回一个新的Promise对象,那么这些Promise对象的状态如何确定呢?

then()catch()的回调执行结果直接决定新的Promise状态,即它们的返回值决定了新的Promise状态

  • 如果返回的是非Promise值(number、string、object、bool),新Promise状态都为fulfilled
  • 如果返回的是另一个Promise对象,新Promise会“继承”这个Promise的状态和结果
  • 回调函数抛出错误(throw),新Promise状态为rejected
  • 回调函数没有返回值(默认返回undefined),新Promise状态为fulfilled
// 返回非Promise值,新Promise状态为fulfilled
const promise1 = new Promise((resolve) => {resolve('成功');
}).then(() => {console.log("promise1:第一个then,我返回了一个布尔值");return false;
}).then((value) => {console.log("promise1:上一个promise是fulfilled",value);
}).catch((error) => {console.log("promise1:上一个promise是rejected",error);
})
// 第一个then,我返回了一个布尔值
// 上一个promise是fulfilled false// 返回Promise对象,新Promise状态由返回的Promise对象决定
const promise2 = new Promise((resolve) => {resolve('成功');
}).then(() => {console.log("promise2:第一个then,我返回了一个Promise对象");return new Promise((resolve, reject) => {reject('失败');});
}).then((value) => {console.log("promise2:上一个promise是fulfilled",value);
}).catch((error) => {console.log("promise2:上一个promise是rejected",error);
})
// 第一个then,我返回了一个布尔值
// 上一个promise是rejected 失败// 抛出错误,新Promise状态为rejected
const promise3 = new Promise((resolve) => {resolve('成功');
}).then(() => {console.log("promise3:第一个then,我抛出一个错误");throw new Error('错误');
}).then((value) => {console.log("promise3:上一个promise是fulfilled",value);
}).catch((error) => {console.log("promise3:上一个promise是rejected",error);
})
// 第一个then,我抛出一个错误
// 上一个promise是rejected Error: 错误 at C:\Users\Administrator\Desktop\typescriptStudy\promise.js:36:11

效果

链式Promise返回值

then()catch()中,return是可选的:

  • 若需要将当前回调的结果传递给下一个链式调用,必须用return(否则下一个回调接受逇是undefined)
  • 若不需要传递给下一个Promise,可以省略return(默认返回undefined)

finally()中,return无意义的

无论finally的回调是否return值,都不会影响下一个链式调用接收的结果,因此通常不需要再finally中使用return

then、catch、finally无法接收到finally的return值:

const promise = new Promise((resolve, reject) => {resolve('成功!');
}).then((value) => {console.log("then成功",value);
}).finally(() => {console.log("finally");return "finally返回值"
}).then((value) => {console.log("then成功2",value);
})

效果

Promise值穿透

then()catch没有传入对应的回调函数时,Promise会将上一个环节的结果原封不动的传递给下一个对应的回调

then()方法的值穿透

then()没有传入第一个参数fulfilled回调)时,会自动将上一个Promise的成功结果传递给下一个then()fulfilled回调

Promise.resolve(100).then() // 没有传入回调函数,因此值穿透.then() // 同样没有传入回调函数,继续值穿透.then((value) => {console.log(value); // 输出:100})

catch()方法的值穿透

catch()没有传入回调函数时,也会和then()一样将上一个Promise的结果传递给下一个rejected回调

Promise.reject('错误').catch().catch().catch((error) => {console.log(error);})

finally方法的值穿透

finally本身不接收参数,但它仍然可以值穿透

Promise.resolve("成功").finally().then((value) => {console.log(value);})

总结

值穿透不会改变Promise的状态,只是“原样传递”:

  • 上一个是fulfiiled状态,穿透后下一个依然是fulfilled
  • 上一个是rejected状态,穿透后下一个依然是rejected

Promise.race

Promise.race接收一个Promise数组,只要有一个Promise的状态改变,race就会捕获并返回该Promise

// Promise.race()
const p1 = new Promise((resolve) => {setTimeout(() => {resolve(1);},3000)
})
const p2 = new Promise((resolve) => {setTimeout(() => {resolve(2);},1000)
})
Promise.race([p1, p2]).then((value) => {console.log(value);
})

根据这个特性,我们可以很方便的实现一个超时器,当某任务超时,执行超时器函数。

// Promise实现超时器
// 模拟一个任务,它执行需要3s
const targetTask = new Promise((resolve, reject) => {setTimeout(() => {resolve("任务完成");},3000)
})
// 封装超时器容器
const timeoutFunction = (task,delay) => {// 超时器函数const timeout = (delay) => {return new Promise((resolve, reject) => {setTimeout(() => {reject("任务超时");},delay)})}return Promise.race([task, timeout(delay)]);
}
// 调用超时器容器
timeoutFunction(targetTask,2000).then((value) => {console.log(value);}).catch((error) => {console.log(error);})

Promise错误捕获的边界

catch只能捕获其前面的错误

当一个错误已经被前面的catch捕获时,该错误就不会被当前的catch捕获了

Promise.reject("error1").then(() => {console.log("我不会被执行");}).catch((error) => {// 捕获error1console.log("error:", error);throw "error2"}).then(() => {console.log("我不会被执行");}).catch((error) => {// 捕获error2console.log("error:", error);});

catch捕获规则

catch可以捕获同步错误(throw、回调执行出错)和异步操作中通过reject抛出的错误

但是无法直接捕获Promise执行器或回调中异步代码的同步错误

new Promise((resolve, reject) => {setTimeout(() => {console.log('我不会被捕获');throw "Promise构造器内的错误"},0);
}).catch((error) => {console.log('error:',error); // 无效,无法被捕获
})new Promise((resolve, reject) => {setTimeout(() => {console.log('我会被捕获');reject("Promise构造器内的错误")},0);
}).catch((error) => {console.log('error:',error);
})

效果

第一个Promise错误没有被捕获,从而导致代码被堵塞,这是因为Promise构造器内错误无法被catch()捕获,我们可以手动添加try catch语句,来捕获同步代码错误:

new Promise((resolve, reject) => {setTimeout(() => {try {console.log('我会被捕获');throw "Promise构造器内的错误"}catch(error) {console.log('error:',error);}},0);
}).catch((error) => {console.log('error:',error); // 无效,无法被捕获
})

效果

其它

更多JavaScript学习可以参考我的专栏:

JavaScript_是洋洋a的博客-CSDN博客

http://www.dtcms.com/a/411709.html

相关文章:

  • 建立网站需要备案吗网络科技公司起名字大全免费
  • solidworks ppo 试做1
  • Matter over Thread方案,如何助力智能家居生态互通?
  • 创办网站需要怎么做wordpress 点评类网站
  • 网站开发与运营怎么样0基础网站开发
  • mp3链接地址制作网站网站建设与开发选题
  • Dify 从入门到熟悉100 天的学习大纲
  • 为什么做的网站要续费东莞cms建站模板
  • 安徽省高速公路建设指挥部网站为什么实验楼网站上做实验这么卡
  • Java Web应用开发——第一章:Java Web概述测验
  • 北京网站建设哪家好免费正能量不良网站推荐
  • 高端网站建设公司有哪些项目南京房地产开发公司
  • 网络编程
  • VGG改进(11):基于WaveletAttention的模型详解
  • 安徽建筑大学学工在线网站代理网游
  • 网站流量是什么承包工程在哪个网站
  • 游标查询在对话历史场景下的独特优势
  • 临沂做网站的在哪里看看铜陵新闻
  • 密云区社区建设网站蚌埠网站建设中心
  • 参考数据和主数据考试考点及关系梳理
  • 临沂供电公司网站看网红直播做爰的网站
  • 最小修改com.anji-plusjar包使之能够在springboot3使用
  • 武安网站建设价格网站建设公司做ppt吗
  • 【Arxiv 2025】重磅发布!全新傅里叶残差通道注意力模块FRCA,助显著性目标检测与跨模态融合,精准提升深度学习性能!
  • 网站空间期限查询企业取名字
  • 不良网站进入窗口免费正能量网站经营性备案需要什么资料
  • 摄影网站建设的功能有哪些不会编程 做网站
  • JVM 类加载
  • golang如何四舍五入到2位小数
  • ps临摹图片做网站的图片犯法吗黄冈贴吧