JavaScript高级(十四)----prmise
异步请求的处理方式
回调函数
所谓的回调函数就是函数作为参数的传递,在一个函数内部调用另一个函数,调用的同时可以把内部函数的数据传递出来,他的使用场景就是异步操作,数据需要等待一段时间才能返回的情况下可以使用回调函数
function foo(url, successCallback, failtureCallback) {// 假设这是网络请求,需要请求完毕才能返回给用户使用setTimeout(() => {if (url === 'success') {// 假设successCallback callback === 'function'successCallback && successCallback({ code: '200', message: '请求成功' })} else {//failtureCallback callback === 'function'failtureCallback && failtureCallback({ code: '-200', message: '请求失败' })}}, 2000)}foo('failture',res => console.log(res),err => console.log(err))
回调函数处理异步的弊端
- 如果是我们自己封装的函数,那么我们在封装的时候必须要自己设计好callback名称, 并且使用好,否则容易造成不理解。
- 如果我们使用的是别人封装的函数或者一些第三方库, 那么我们必须去看别人的源码或者文档, 才知道它这个函数需要怎么去获取到结果。
- 异步嵌套太多,容易造成回调地狱,代码看起来很不容易理解,可维护可阅读性都不高,找bug要花很多时间。
-
function foo(url, successCallback, failtureCallback) {// 假设这是网络请求,需要请求完毕才能返回给用户使用setTimeout(() => {if (url === 'success') {successCallback && successCallback({ code: '200', message: '请求成功' })} else {failtureCallback && failtureCallback({ code: '-200', message: '请求失败' })}}, 1000)}foo('success',// 成功回调(res) => {console.log(`第一次数据请求成功,接着请求第二次数据${res.code}`)foo('success', (res) => {console.log(`第二次数据请求成功,接着请求第三次数据${res.code}`)foo('success', (res) => {console.log(`第三次数据请求成功,接着请求第四次数据${res.code}`)foo('success', (res) => {console.log(`第四次数据请求成功,接着请求第五次数据${res.code}`)foo('success', (res) => {console.log(`第五次数据请求成功,接着请求第六次数据${res.code}`)foo('failture', (res) => {console.log(`第六次数据请求成功,接着请求第七次数据${res.code}`)}, (err) => { console.log(`第六次数据请求失败,gg了${err.code}`) })}, (err) => { console.log(err) })}, (err) => { console.log(err) })}, (err) => { console.log(err) })}, (err) => { console.log(err) })},// 失败回调(err) => { console.log(err) })上面代码就是典型的回调地狱,试问,如果你在真实项目开发中遇见这样的代码,你能够分析出问题的所在吗?所以这不是一种合理解决异步的方案。
Promise
Promise是一个类,实现异步编程的方法。
Promise的状态一旦被确定下来,无法被更改,resolve、reject两个函数不会代码禁止向下执行,为了防止继续向下执行,要加上return。
Promise的三个状态
- 待定( pending ) : 初始状态,既没有被兑现,也没有被拒
- 已兑现( fulfilled ) : 意味着操作已经完成 resolve
- 已拒绝 (rejected):意味着操作失败 reject
resolve不同值的区别
- 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数
const promise = new Promise((resolve, reject) => { resolve("普通值") });promise.then(res => {console.log(res)}, err => { })
- 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
const promise = new Promise((resolve, reject) => {resolve(new Promise((resolve, reject) => {reject("我是新的promies, 我要改变之前promise的状态,这里会执行err")}))});promise.then(res => {console.log(res)}, err => {console.log(err)})
- 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据 then方法的结果来决定Promise的状态
const promise = new Promise((resolve, reject) => {const obj = {name: 'obj',then(resolve, reject) {reject('传入一个对象,对象里面有then方法,会改变之前promise的状态')}}resolve(obj)});promise.then(res => {console.log(res)}, err => {console.log(err)})then 方法的参数
// then方法接受两个参数new Promise((resolve, reject) => {reject('嘿嘿')}).then(res => {console.log('resolve触发的回调函数');},err => {console.log('reject触发的回调函数');})// 等价于new Promise((resolve, reject) => {reject('嘿嘿')}).then(res => { console.log('resolve触发的回调函数') }).catch(err => { console.log('reject触发的回调函数') })then 方法多次调用
const promise = new Promise((resolve, reject) => {reject('嘿嘿嘿')})promise.then(res => { console.log(res) }).catch(err => { console.log(err) })promise.then(res => { console.log(res) }).catch(err => { console.log(err) })then/catch 方法返回值
then/catch方法本身返回的就是一个Promise,所以我们可以进行链式调用。
-
// catch打印完后又返回了一个promise 所以后面的then又会打印new Promise((resolve, reject) => {reject('嘿嘿')}).then(res => { console.log('resolve触发的回调函数'); }).catch(err => { console.log('reject触发的回调函数'); return 123 }).then(res => { console.log(res) })finally 方法
finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会被执行的代码
new Promise((resolve, reject) => {reject('reject')}).then(res => { console.log(res) }).catch(err => { console.log(err) }).finally(() => { console.log('我是最后被执行的') })all 方法
它的作用是将多个Promise包裹在一起形成一个新的Promise。新的Promise状态由包裹的所有Promise共同决定。
// 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组; const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('1')}, 1000)})const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('2')}, 2000)})const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('3')}, 3000)})Promise.all([p3, p2, p1]).then(res => {console.log(res)}).catch(err => {console.log(err)})//当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('1')}, 1000)})const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject('2')}, 2000)})const p3 = new Promise((resolve, reject) => {setTimeout(() => {reject('3')}, 3000)})Promise.all([p3, p2, p1]).then(res => {console.log(res)}).catch(err => {console.log(err)})allSettled 方法
all方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态。
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(11111)}, 1000);})const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject(22222)}, 2000);})const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(33333)}, 3000);})// allSettledPromise.allSettled([p1, p2, p3]).then(res => {console.log(res)}).catch(err => {console.log(err)race 方法
如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法。
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('1')}, 1000)})const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject('2')}, 998)})const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('3')}, 1002)})// 不管是resolve 还是reject 谁先有结果,那么就使用谁的结果Promise.race([p1, p2, p3]).then(res => { console.log(res) }).catch(err => { console.log(err) })any 方法
和race方法是类似的,any方法会等到一个fulfilled状态,才会决定新Promise的状态,如果所有的Promise都是reject的,那么会报一个AggregateError的错误。
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('1')}, 1000)})const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject('2')}, 998)})const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve('3')}, 1002)})// 会打印p1 Promise.any([p1, p2, p3]).then(res => { console.log(res) }).catch(err => { console.log(err) })
相关文章:
JavaScript高级(十四)----prmise
异步请求的处理方式 回调函数 所谓的回调函数就是函数作为参数的传递,在一个函数内部调用另一个函数,调用的同时可以把内部函数的数据传递出来,他的使用场景就是异步操作,数据需要等待一段时间才能返回的情况下可以使用回调函数…...
28 OpenCV 轮廓周围绘制图形
文章目录 approxPolyDP 轮廓周围绘制矩形boundingRectminAreaRect绘制圆和椭圆示例 approxPolyDP 轮廓周围绘制矩形 approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)curve:输入点集,二维点向量的集合appro…...
校企合作,助力人才培养——黄冈师范学院-唯众 “实习实训基地”揭牌仪式顺利举行
3月20日上午,黄冈师范学院计算机学院院长何中林、教务处实习科科长雷汝琳以及计算机学院实验室主任肖飞一行三人,莅临唯众进行参观交流。唯众总经理冉柏权、销售总监舒敏以及董事长助理代西凯进行了热情接待。双方就如何更好地结合企业需求与学院教育资源…...
npm audit fix --force
npm audit fix --force是npm的一个命令,用于自动修复包中的安全漏洞。 其中: - npm audit:审查项目中的依赖包,检查是否存在已知的安全漏洞。 - fix:自动安装相关的补丁来修复发现的漏洞。 - --force:强制安装补丁版本,即使出现不兼容也强制更新。 所以npm audit fix --fo…...
递增四元组
解法: 首先都可以想到dp[i]:第i个元素结尾的递增四元组有dp[i]个 然后发现有一组数据:2,3,6,1,5,8。会出现6结尾和5结尾的递增三元组,也就是未来的决策受过去影响,专业的说就是有后效性。需要强化约束条件࿰…...
蓝桥杯每日一题——棋盘
问题描述 小蓝拥有 n xn 大小的棋盘,一开始棋盘上全都是白子。小蓝进行了 m 次操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色,黑色棋子变为白色)请输出所有操作做完后棋盘上每个棋子的颜色。输入格式 输入的…...
QT6实现创建与操作sqlite数据库及读取实例(一)
一.Qt为SQL数据库提供支持的基本模块(Qt SQL) Qt SQL的API分为不同层: 驱动层 SQL API层 用户接口层 1.驱动层 对于Qt 是基于C来实现的框架,该层主要包括QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlPlug…...
第十四届蓝桥杯JavaB组省赛真题 - 阶乘求和
/ 10^9考虑前九位,% 10^9保留后9位 解题思路: 求获取结果的后九位数字,需要对10^9取余,因为202320232023这个数字的阶乘太大,必须要减少计算量,因为当一个整数乘以10^9后对其取余,那么结果都为0。 所以我…...
Java毕业设计 基于springboot医院挂号系统 医院管理系统
Java毕业设计 基于springboot医院挂号系统 医院管理系统 springboot医院挂号系统 医院管理系统 功能介绍 用户:登录 首页 个人资料 修改密码 门诊管理 用户挂号 医生:登录 首页 个人资料 修改密码 门诊管理: 用户挂号 处方划价 项目划价 项目缴费 项目…...
【MySQL】基本查询(1)
【MySQL】基本查询(1) 目录 【MySQL】基本查询(1)表的增删改查Create单行数据 全列插入多行数据 指定列插入插入否则更新替换 RetrieveSELECT 列全列查询指定列查询查询字段为表达式为查询结果指定别名结果去重 WHERE 条件英语不…...
一文讲清!进销存管理系统如何实现锁库及库存冻结?计算月加权平均成本?
进销存管理系统中的锁库及库存冻结如何实现?进销存管理系统如何计算月加权平均成本?进销存管理系统又该如何统计和预测采购需求?这些进销存管理难题困扰着许多企业管理者。本文将结合数年从业经验,深入探讨这些进销存管理难题&…...
将本地项目上传至码云
1.打开git,然后进入到项目目录 2.进入到项目目录,然后进行git的初始化 成功后本地项目目录内会多出一个“.git”文件: 指令介绍: git init -- 建立本地仓库 3.在码云上创建仓库,名为“MyMoney” 创建过程参考&…...
虚拟化技术
前言 大家好我是jiantaoyab,这是我所总结作为学习的笔记第十八篇,在这里分享给大家,这篇文章讲虚拟技术就是大家平时用到的云服务器是什么。 虚拟机技术变迁 虚拟机(Virtual Machine)技术,其实就是指在现…...
鸿蒙一次开发,多端部署(一)简介
背景 随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的…...
数据结构——单向链表(C语言版)
在数据结构和算法中,链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。在C语言中,我们可以使用指针来实现单向链表。下面将详细介绍如何用C语言实现单向链表。 目录 1. 定义节点结构体 2. …...
ideaSSM 工厂效能管理系统bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 idea 开发 SSM 工厂效能管理系统是一套完善的信息管理系统,结合SSM框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库ÿ…...
Java反射机制的讲解及其示例说明
Java 反射机制是指在运行时动态地获取类的信息以及操作对象的方式。它允许程序在运行时检查和操作类、方法、属性等,而不需要在编译时就确定这些属性。通过反射机制,我们可以在运行时动态地创建对象、调用方法、获取属性等。 Java 反射机制提供了以下主…...
20240309web前端_第二周作业_完成游戏导航栏
作业:游戏导航栏 成果展示: 完整代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0…...
五、大模型-Prompt
一、prompt是什么 在大型语言模型集成中,"prompt" 是指您向模型提供的输入文本或指令,以引导模型生成特定类型的响应。这个 prompt 可以是一个问题、一段描述、一个任务说明,甚至是一部分对话历史记录等。通过设计和优化 prompt&a…...
【网络安全】 MSF提权
本文章仅用于信息安全学习,请遵守相关法律法规,严禁用于非法途径。若读者因此作出任何危害网络安全的行为,后果自负,与作者无关。 环境准备: 名称系统位数IP攻击机Kali Linux6410.3.0.231客户端Windows 76410.3.0.234…...
FCEUX终极指南:从怀旧游戏到专业调试的完整NES模拟器教程
FCEUX终极指南:从怀旧游戏到专业调试的完整NES模拟器教程 【免费下载链接】fceux FCEUX, a NES Emulator 项目地址: https://gitcode.com/gh_mirrors/fc/fceux FCEUX是一款功能强大的开源NES模拟器,让你在现代电脑上完美重温经典红白机游戏。无论…...
用Python和MNE库玩转BCI Competition IV 2a脑电数据集:从数据加载到可视化全流程
用Python和MNE库玩转BCI Competition IV 2a脑电数据集:从数据加载到可视化全流程当你第一次接触脑电信号处理时,面对原始数据文件可能会感到无从下手。BCI Competition IV 2a数据集作为脑机接口领域的经典基准数据,包含了9名受试者四种运动想…...
Blender渲染通道完全指南:如何像电影后期一样,分离出深度、阴影与反射图
Blender渲染通道完全指南:影视级后期制作的深度解析在数字内容创作领域,Blender已经从一个简单的3D建模工具成长为能够处理复杂视觉特效的全流程解决方案。对于追求影视级质量的中高级用户而言,掌握渲染通道技术是提升作品专业度的关键一步。…...
从社交关系到分子结构:图解GCN(图卷积网络)到底在‘看’什么?
从社交关系到分子结构:图解GCN(图卷积网络)到底在‘看’什么?想象一下,你刚搬到一个新社区,想快速了解周围的邻居。最直接的方式是什么?不是挨家挨户敲门,而是通过社区活动认识几位关…...
论文创新点像挤牙膏?导师强推这几个AI论文平台
想写论文又快又好,关键是用对 AI 工具、走对流程——资深教授普遍推荐:千笔AI(中文全流程首选) 豆包学术版(轻量高效) DeepSeek 学术版(理工 / 长文本) Grammarly Academicÿ…...
2026 新视角:化妆品开发的底层逻辑,做好一款产品,从选对原料开始
在化妆品研发链条中,配方架构、生产工艺、包装设计固然重要,但决定一款产品上限的,永远是原料。一款稳定、安全、表现优异的护肤成品,离不开纯净、达标、批次一致的优质原料。对于品牌方、配方师、代工企业而言,原料不…...
SAP-ABAP:变量、常量、结构与内表声明(10篇博客合集) 第五篇:声明时的键值设计技巧:结构与内表的主键、非主键配置指南
变量、常量、结构与内表声明(10篇博客合集) 第五篇:声明时的键值设计技巧:结构与内表的主键、非主键配置指南如果把内表比作一张内存中的“数据库表”,那么键就是这张表的索引甚至主键。键的设计直接决定了数据的唯一性…...
网络配置工具类详解
CNet 网络配置工具类详解平台:仅支持 Linux,大量使用 ioctl 系统调用一、概述 CNet 是一个 纯静态方法的网络配置工具类,封装了 Linux 下常用的网络操作:功能类别涵盖内容IP 地址读取/设置本机 IP、子网掩码网关读取/添加/删除/设…...
为什么你的DeepSeek微调loss震荡不止?(Meta/DeepSeek联合团队未公开的梯度裁剪+LoRA初始化双校准协议)
更多请点击: https://codechina.net 第一章:DeepSeek微调loss震荡的根本归因剖析 DeepSeek系列模型在微调过程中频繁出现loss剧烈震荡现象,其本质并非单一因素所致,而是数据、优化器、梯度动态与模型结构四者耦合失稳的系统性表现…...
OpenRASP原理与实战:Java应用层实时防护技术详解
1. 为什么我宁愿花三天部署OpenRASP,也不愿再写第五个自定义WAF过滤器去年冬天,我在给一家做在线教育SaaS平台做安全加固时,连续踩了三个坑:第一次用NginxLua写了套SQL注入规则,结果学生提交的“SELECT * FROM courses…...
