Web前端Promise

Promise介绍与使用

Promise是什么?

1.抽象表达:

  • Promise是一门新的技术(ES6规范)
  • Promise是JS中进行异步编程的新解决方案
  • 备注:旧方案是单纯使用回调函数

2.具体表达:

  • 从语法上来说:Promise是一个构造函数
  • 从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

异步编程

  • fs文件操作
require('fs').readFile('./index.html',(err,data)=>{})
  • 数据库操作
  • AJAX
$.get('/server',(data)=>{})
  • 定时器
setTimeout(()=>{},2000)

指定回调函数的方式更加灵活

1.旧的:必须在启动异步任务前指定

2.promise:启动异步任务=>返回promise对象=>

给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个) 

支持链式调用,可以解决回调地狱问题

回调地狱

回调地狱嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件

特点:不便于阅读,不便于异常处理

Promise实践练习-fs模块

const fs=require('fs')
// 回调函数形式
// fs.readFile('./resource/content.txt',(err,data)=>{
//   // 如果出错 则抛出错误
//   if(err) throw err
//   // 输出文件内容
//   console.log(data.toString())
// })
// Promise形式
let p=new Promise((resolve,reject)=>{fs.readFile('./resource/content.txt',(err,data)=>{// 如果出错if(err)reject(err)// 如果成功resolve(data)})
})
p.then(value=>{console.log(value.toString())
},reason=>{console.log(reason)
})

 Promise实践练习-AJAX请求

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div class="container"><h2 class="page-header">Promise 封装AJAX操作</h2><button class="btn btn-primary" id="btn">点击发送AJAX</button></div><script>// 接口地址 http://api.apiopen.top/getJoke// 获取元素对象const btn=document.querySelector('#btn')btn.addEventListener('click',function(){const p=new Promise((resolve,reject)=>{// 1.创建对象const xhr=new XMLHttpRequest()// 2.初始化xhr.open('GET','https://api.apiopen.top/getJoke')// 3.发送xhr.send()// 4.处理响应结果xhr.onreadystatechange=function(){if(xhr.readyState===4){// 判断响应状态码if(xhr.status>=200&&xhr.status<300){// 控制台输出响应体resolve(xhr.response)}else{// 控制台输出响应状态码reject(xhr.status)}}}})p.then(value=>{console.log(value)},reason=>{console.warn(reason)})})</script>
</body>
</html>

封装读取文件函数

/***封装一个函数mineReadFile读取文件内容参数:path 文件路径返回:promise 对象 **/
function mineReadFile(path){return new Promise((resolve,reject)=>{require('fs').readFile(path,(err,data)=>{// 判断if(err) reject(err)// 成功resolve(data)})})
}
mineReadFile('./resource/content.txt').then(value=>{console.log(data)
},reason=>{console.warn(reason)
})

util.promisify(original)

传入一个遵循常见错误优先的回调风格的函数(即以(err,value)=>...回调作为最后一个参数),并返回一个返回promise的版本

// util.promisify方法
// 引入util模块
const util=require('util')
// 引入fs模块
const fs=require('fs')
// 返回一个新的函数
let mineReadFile=util.promisify(fs.readFile)//让fs.readFile返回一个promise对象,将回调函数风格的方法转为promise风格的方法
mineReadFile('./resource/content.txt').then(value=>{},reason=>{})

Promise封装练习

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 封装一个函数sendAJAX发送GET AJAX请求// 参数   URL// 返回结果 Promise对象function sendAJAX(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest()xhr.responseType='json'xhr.open('GET',url)xhr.send()// 处理结果xhr.onreadystatechange=function(){if(xhr.readyState===4){// 判断成功if(xhr.status>=200&&xhr.status<300){resolve(xhr.response)}else{reject(xhr.status)}}}})}sendAJAX('https://api.apiopen.top/getJoke').then(value=>{console.log(value)},reason=>{console.warn(reason)})</script>
</body>
</html>

Promise的状态改变

  1. pending变为resolved
  2. pending变为rejected

说明:只有这两种,且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason

 Promise的状态

实例对象中的一个属性PromiseState

  • pending 未决定的
  • resolved/fullfilled成功
  • rejected失败

Promise对象的值

实例对象中的另一个属性 PromiseResult

保存着异步任务(成功或失败)的结果

Promise的基本流程

 API

1.Promise构造函数:Promise(excutor){}

  1. executor函数:执行器(resolve,reject)=>{}
  2. resolve函数:内部定义成功时我们调用的函数value=>{}
  • reject函数:内部定义失败时我们调用的函数reason=>{}

说明:executor会在Promise内部立即同步调用(非异步),异步操作在执行器中执行

2.Promise.prototype.then方法:(onResolved,onRejected)=>{}

  1. onResolved函数:成功的回调函数(value)=>{}
  2. onRejected函数:失败的回调函数(reason)=>{}

说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象

3.Promise.prototype.catch方法:(onRejected)=>{}

  • onRejected函数:失败的回调函数(reason)=>{}

4.Promise.resolve()方法:(value)=>{}

  • value:成功的数据或promise对象

说明:返回一个成功/失败的promise对象

如果传入的参数为非promise类型的对象,则返回的结果为成功promise对象

如果传入的参数为Promise对象,则参数的结果决定了resolve的结果

5.Promise.reject方法:(reason)=>{}

  • reason:失败的原因

说明:返回一个失败的promise对象

无论传入什么样的数值,结果均为失败的promise对象

6.Promise.all方法:(promises)=>{}

  • promises:包含n个promise的数组

说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败

        let p1 = new Promise((resolve, reject) => {resolve('ok');})let p2 = new Promise((resolve, reject) => {resolve('hello');})let p3 = new Promise((resolve, reject) => {reject('error');})let result = Promise.all([p1, p2, p3]);console.log(result);

7.Promise.race方法:(promises)=>{} 

  • promises:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

Promise.race方法是需要传递一个参数,参数为数组,数组中的内容表示的是Promise实例化对象如果有最先到达状态的(pending来更改成fulfilled或者是rejected),不管是成功状态还是失败的状态,都将以这个对象的状态和结果值为准

 

        const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1);}, 1000)})const p2 = new Promise((resolve, reject) => {setTimeout(() => {reject(2);}, 3000)})const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(3);}, 5000)})const result = Promise.race([p3, p1, p2]);console.log(result);

promise的几个关键问题

如何改变promise的状态?

  1. resolve(value):如果当前是pending就会变为resolved
  2. reject(reason):如果当前是pending就会变为rejected
  3. 抛出异常:如果当前是pending就会变为rejected
        let p1 = new Promise((resolve, reject) => {//成功// resolve('success');//失败// reject('error');//抛出异常// throw ' 出问题啦,你如果在这么写肯定是有问题的,有没有良心~~~';//状态只能更改一次reject('error');resolve('ok');})console.log(p1);

一个promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时就会调用

        let p1 = new Promise((resolve, reject) => {// resolve('ok');// reject('error');// throw '异常'})console.log(p1);p1.then(value => {console.log(value);}, reason => {console.log(reason);})p1.then(value => {console.log(value);}, reason => {console.log(reason);})

改变promise状态和指定回调函数谁先谁后?

(1)都有可能,正常情况下是先指定回调函数再改变状态,但也可以先改状态再指定回调

若执行器函数中为同步任务,则先修改状态,后指定回调

若执行器函数中为异步任务,则先指定回调,在更改状态,更为常见 [promise主要是为了执行异步任务]

(2)如何先改状态再指定回调?

  1. 在执行器中直接调用resolve()/reject()
  2. 延迟更长时间才调用then()

(3)什么时候才能得到数据?

  1. 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
  2. 如果先改变的是状态,那当指定回调时,回调函数就会调用,得到数据

(4)promise.then()返回的新promise的结果状态由什么决定?

  1. 简单表达:由then()指定的回调函数执行的结果决定
  2. 详细表达:
  • 如果抛出异常,新promise变为rejected,reason为抛出的异常
  • 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
  • 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
        const p1 = new Promise((resolve, reject) => {resolve('ok');})const result = p1.then(value => {//console.log(value);// return value;return new Promise((resolve, reject) => {//resolve('success');reject('error');})}, reason => {console.log(reason);})console.log(result);

(5)promise如何串连多个操作任务?

  1. promise的then()返回一个新的promise,可以开成then()的链式调用
  2. 通过then的链式调用串连多个同步/异步任务
        new Promise((resolve, reject) => {//reject('error');resolve('success');}).then(value => {console.log(value);console.log(222);}).then(value => {console.log(value);//返回结果为undefined}).then(value => {console.log(value);}, reason => {console.log(reason);})

(6)promise异常穿透

  1. 当使用promise的then链式调用时,可以在最后指定失败的回调
  2. 前面任何操作出了异常,都会传到最后失败的回调中处理
        new Promise((resolve, reject) => {console.log(111);reject('error');}).then(value => {console.log(222);}).then(value => {console.log(value);}).then(value => {console.log(value);}).catch(reason => {console.log(reason);})

(7)中断promise链

  1. 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
  2. 办法:在回调函数中返回一个pendding状态的promise对象
        new Promise((resolve, reject) => {resolve(1);}).then(value => {console.log(value);}).then(value => {console.log(22222);}).then(value => {console.log(33333);//return false;//throw '异常';return new Promise(() => { })}).then(value => {console.log(44444);}).then(value => {console.log(55555);}).catch(reason => {console.log(reason);})

async与await

async函数

  • 函数的返回值为promise对象
  • promise对象的结果由async函数执行的返回值决定
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>async函数</title>
</head><body><script>//以前代码// const p1 = new Promise((resolve, reject) => {//     resolve('ok');// })// //只不过是从原来的回调地狱写法修改成了回调函数的链式写法,换汤不换药// //使用async结合await的终极目标:就是同步的代码来完成异步的功能// p1.then(value => {//     console.log(value);// }, reason => {//     console.log(reason);// }).then(value => {//     console.log(value);// }, reason => {//     console.log(reason);// })//任何的函数都可以被声明成一个async函数//因为要实现的就是异步功能(定时器、ajax请求...)//可能是要将实现的功能封装到一个函数之中,为了更好的表示函数之中是异步,所以在函数的前面添加一个asyncasync function main() {//函数的内部可以添加任意的语句来执行,但是其真正的目的主要是为了得到一个Promise对象的状态以及结果值// console.log('哈哈哈哈');//情况1:返回非Promise对象的数据// return 100;//情况2:返回的是Promise对象//返回的这个Promise实例化对象的状态以及结果值将直接影响结果产生的Promise实例化对象的状态和结果值// return new Promise((resolve, reject) => {//     // resolve('ok');//     reject('error');// })//情况3:抛出异常// throw '出错啦';throw new Error('出错啦');}//调用let result = main();result.then(value => {console.log(value);}, reason => {console.log(reason);})</script>
</body></html>
  1. await表达式

  • await右侧的表达式一般为promise对象,但也可以是其他的值
  • 如果表达式为promise对象,await返回的是promise成功的值
  • 如果表达式是其它值,直接将此值作为await的返回值

注意:

  • await必须写在async函数中,但async函数中可以没有await
  • 如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>await表达式</title>
</head><body><!--1、async函数结合await表达式1.1 async函数中不一定要完全结合await1.2 有await的函数一定是async函数2、await相当于then,可以直接拿到成功的Promise实例化对象的结果值3、await一定要写在async函数之中,但是async函数之中可以没有await4、如果await表达式后面是Promise实例化对象,则await返回的是Promise的成功的结果值5、如果await表达式后面的其他值,则会直接将这个值作为await的返回值--><script>async function main() {//内部执行异步的功能,并且得到成功的结果数据值//1、如果await右侧为非Promise类型的数据,await后面的值是什么,得到的结果就是什么// let rs = await 100;// console.log(rs);//2、如果await右侧为Promise成功类型的数据// let rs = await new Promise((resolve, reject) => {//     resolve('ok');// })// console.log(rs);// let rs = await Promise.resolve('okk');// console.log(rs);//3、如果await右侧为失败的Promise类型数据,需要try...catch来捕获try {// let rs = await new Promise((resolve, reject) => {//     reject('error');// })// console.log(rs);let rs = await Promise.reject('error');console.log(rs);} catch (e) {console.log(e);}//有了try...catch后续的代码将继续执行console.log(1111);}//调用main();</script>
</body></html>

使用async和await异步读取文件

//1、导入模块
const fs = require('fs');
const { promisify } = require('util');//2、创建async函数
async function main() {//读取文件let myreadfile = promisify(fs.readFile);try {let one = await myreadfile('./resource/1.txt');let two = await myreadfile('./resource/2.txt');let three = await myreadfile('./resource/3.txt');console.log(one + two + three);} catch (e) {console.log(e);}
}
//调用函数
main();

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

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

相关文章

Android SurfaceView 组件介绍,挖洞原理详解

文章目录 组件介绍基本概念关键特性使用场景 SurfaceHolder介绍主要功能使用示例 SurfaceView 挖洞原理工作机制 使用SurfaceView展示图片示例创建一个自定义的 SurfaceView类在 Activity 中使用 ImageSurfaceView注意事项效果展示 组件介绍 在 Android 开发中&#xff0c;Sur…

HiFi-GAN——基于 GAN 的声码器,能在单 GPU 上生成 22 KHz 音频

拟议的 HiFiGAN 可从中间表征生成原始波形 源码地址&#xff1a;https://github.com/NVIDIA/DeepLearningExamples 论文地址&#xff1a;https://arxiv.org/pdf/2010.05646.pdf 研究要点包括 **挑战&#xff1a;**基于 GAN 的语音波形生成方法在质量上不及自回归模型和基于流…

纯前端小游戏,4096小游戏,有音效,Html5,可学习使用

// 游戏开始运行create: function(){this.fieldArray [];this.fieldGroup this.add.group();this.score 0;//4096 增加得分this.bestScore localStorage.getItem(gameOptions.localStorageName) null ? 0 : localStorage.getItem(gameOptions.localStorageName);for(var …

vscode及pycharm配置Python文件模板

一、vscode配置方法 第一步&#xff0c;依次点击“File”->“preference”->“Configure User Snippets”&#xff0c;在弹出的框中输入Python&#xff0c;打开python.json 文件 第二步&#xff0c;python.json 文件中输入以下内容&#xff1a; {"Python Template…

QtC++ 设计模式(五)——状态模式

状态模式 序言理解源码 序言 设计模式只是一个抽象的设计模式方法&#xff0c;并不是一个固定使用的搭配&#xff0c;就算是普通switch语句&#xff0c;Map&#xff0c;乃至状态机都是状态模式的其中一种实现方法 状态模式看起来好像和策略模式差不多&#xff0c;主要是其的侧…

Java记事本工具Notepad++

常见的高级记事本 Editplus、Notepad、Sublime Notepad软件的安装和使用 安装&#xff1a;傻瓜式安装 1、选择中文-->【OK】 2、点击【下一步】 3、协议点击【我接受】 4、选择安装路径-->【下一步】 5、点击【下一步】 6、最后点击【安装】 7、将运行取消-->点击…

戴尔电脑开机出现no boot device found错误提示原因分析及解决方法

戴尔电脑是一款不的品牌,戴尔电脑一直以来都是以IT直销享誉全球的。而旗下的戴尔笔记本&#xff0c;更是深受用户们的追捧和喜爱。最近有网友反馈戴尔电脑开机出现no boot device found错误提示是怎么回事&#xff1f;后来发现有很多网友将引导模式改成legacymbr后发现启动时出…

2024-07-18 Unity插件 Odin Inspector8 —— Type Specific Attributes

文章目录 1 说明2 特定类型特性2.1 AssetList2.2 AssetSelector2.3 ChildGameObjectsOnly2.4 ColorPalette2.5 DisplayAsString2.6 EnumPaging2.7 EnumToggleButtons2.8 FilePath2.9 FolderPath2.10 HideInInlineEditors2.11 HideInTables2.12 HideMonoScript2.13 HideReferenc…

对消息队列进行深入学习

目录 1.什么是消息队列。1.1消息队列1.1.1同步的理解1.1.2异步的理解 1.2消息传递与消息队列 2. 消息队列应用场景2.1 异步处理2.2 流量削锋2.3 应用解耦2.4 日志处理2.5 消息通讯2.6 延时任务2.7 广播消费2.8 分布式事务 3. 主流消息队列3.1 RabbitMQ3.1.1 RabbitMQ工作原理3.…

仅两家!云原生向量数据库 PieCloudVector 全项通过信通院「可信数据库」评测

7月16日&#xff0c;2024 可信数据库发展大会在北京隆重举行。大会以“自主、创新、引领”为主题&#xff0c;近百位数据库领域的专家、学者齐聚一堂&#xff0c;带来高质量的数据库技术洞察与实战经验。 本次可信数据库发展大会中&#xff0c;中国信通院正式公布 2024 年上半年…

紫光展锐5G安卓核心板T760__国产手机芯片方案

展锐T760安卓核心板是具备续航和性能更加均衡的5G移动平台。其主要特点包括主流的6400万像素摄像头和高达120Hz的刷新率。 平台采用多模融合的创新架构和AI智能调节技术&#xff0c;从而在5G数据场景下降低了37%的整体功耗&#xff0c;在5G待机场景下降低了18%的整体功耗。 多…

qml 实现一个listview

主要通过qml实现listvie功能&#xff0c;主要包括右键菜单&#xff0c;滚动条&#xff0c;拖动改变内容等&#xff0c;c 与 qml之间的变量和函数的调用。 main.cpp #include <QQuickItem> #include <QQmlContext> #include "testlistmodel.h" int main…

js vue axios post 数组请求参数获取转换, 后端go参数解析(gin框架)全流程示例

今天介绍的是前后端分离系统中的请求参数 数组参数的生成&#xff0c;api请求发送&#xff0c;到后端请求参数接收的全过程示例。 为何会有这个文章&#xff1a;后端同一个API接口同时处理单条或者多条数据&#xff0c;这样就要求我们在前端发送请求参数的时候需要统一将请…

C/C++ xml库

文章目录 一、介绍1.1 xml 介绍1.2 xml 标准1.3 xml 教程1.4 xml 构成 二、C/C xml 库选型2.1 选型范围2.2 RapidXML2.3 tinyxml22.4 pugixml2.5 libxml 五、性能比较5.1 C xml 相关的操作有哪些5.2 rapidxml、Pugixml、TinyXML2 文件读取性能比较 六、其他问题6.1 version和 e…

网络编程-TCP 协议的三次握手和四次挥手做了什么

TCP 协议概述 1. TCP 协议简介 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP 协议提供可靠的通信服务&#xff0c;通过校验和、序列号、确认应答、重传等机制保证数据传输…

MYSQL——库表操作

MYSQL——库表操作 1.1 SQL语句基础1.1.1. SQL简介1.1.2. SQL语句分类1.1.3. SQL语句的书写规范 1.2数据库的操作1.2.1 数据库的登录及退出1.2.2查看数据库 作业 1.1 SQL语句基础 1.1.1. SQL简介 SQL:结构化查询语言(Structured Query Language)&#xff0c;在关系型数据库上…

【ffmpeg入门】安装CUDA并使用gpu加速

文章目录 前言CUDACUDA是什么CUDA 的主要组成部分CUDA 的优点CUDA 的基本编程模型安装CUDA ffmpeg使用gpu加速为什么需要使用gpu加速1. 提高处理速度2. 减少 CPU 负载3. 提高实时处理能力4. 支持高分辨率和复杂编码格式5. 提供更好的可扩展性6. 提高能效 ffmpeg使用gpu加速常用…

【CMU博士论文】结构化推理增强大语言模型(Part 0)

问题 &#xff1a;语言生成和推理领域的快速发展得益于围绕大型语言模型的用户友好库的普及。这些解决方案通常依赖于Seq2Seq范式&#xff0c;将所有问题视为文本到文本的转换。尽管这种方法方便&#xff0c;但在实际部署中存在局限性&#xff1a;处理复杂问题时的脆弱性、缺乏…

单片机主控的基本电路

论文 1.复位电路 2.启动模式设置接口 3.VBAT供电接口 4.MCU 基本电路 5.参考电压选择端口

python处理彩色图像通道拆分与合并

彩色图像通道拆分与合并 1. 使用 opencv2. 使用 numpy 待处理图像 ML.jpg 1. 使用 opencv import cv2 import matplotlib.pyplot as plt import numpy as np # 读取图像 # 读取图像 image cv2.imread(ML.jpg) plt.imshow(image) print(type(image)) # 输出&#xff1a;<…