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;主要是其的侧…

快速上手绿联私有云UGOS Pro系统Docker

要快速上手使用绿联私有云UGOS Pro系统上的Docker&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 设置绿联私有云UGOS Pro 确保你已经成功设置并连接了绿联私有云设备。完成基本的网络配置和用户设置。 2. 访问UGOS Pro系统 通过浏览器访问你的绿联私有云管理界面。…

git记住账号和密码

git记住账号和密码 一、git记住账号和密码1. 全局记住2. 取消全局记住 一、git记住账号和密码 在使用 git 使用 https推送的时候一直需要输入密码。就可以试试下面的方法 1. 全局记住 windows 在git bash 中执行以下命令 linux 直接在bash中执行 git config --global crede…

深入探讨:Node.js、Vue、SSH服务与SSH免密登录

在这篇博客中&#xff0c;我们将深入探讨如何在项目中使用Node.js和Vue&#xff0c;并配置SSH服务以及实现SSH免密登录。我们会一步步地进行讲解&#xff0c;并提供代码示例&#xff0c;确保你能轻松上手。 一、Node.js 与 Vue 的结合 1.1 Node.js 简介 Node.js 是一个基于 …

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后发现启动时出…

Python 中的属性和方法

在面向对象编程&#xff08;OOP&#xff09;中&#xff0c;类是代码的基本构造块。类通过属性和方法来定义对象的状态和行为。在 Python 中&#xff0c;属性和方法是定义类时的重要组成部分。本文将深入探讨 Python 中的属性和方法&#xff0c;帮助你更好地理解它们的用法和意义…

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.…

河南萌新联赛2024第(一)场:河南农业大学(部分题解)

A 造数 题目链接 题意&#xff1a; 给一个整数n&#xff0c;求出最少的操作数使0转化为n 有三种操作方式&#xff1a; 12*2 解题思路&#xff1a; 我们可以将基础的1&#xff0c;2&#xff0c;3分别需要1&#xff0c;1&#xff0c;2次操作&#xff0c; 当n大于3时&#x…

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

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

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

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

gin框架 POST 请求参数绑定 JSON数据ShouldBind 使用注意事项 - 结构体必须定义json标签

gin框架中的请求数据绑定ShouldBind可将前端发送的数据直接绑定到自定义结构体&#xff0c; 但是在POST发送JSON 数据时 需要注意 因为gin框架在底层绑定数据时使用了json对参数进行了反序列化&#xff0c; 所以我们在自定义的结构体中&#xff0c;如果前端发送的JSON中的字段和…

直播架构如何设计核心节点和边缘节点

在直播架构中&#xff0c;核心节点和边缘节点的分工及主要服务是确保直播服务稳定、高效和可扩展的关键。以下是对这些节点的详细描述&#xff1a; 核心节点 核心节点通常位于数据中心&#xff0c;负责处理直播的主要逻辑和数据处理。其主要服务包括&#xff1a; 直播管理后…

Redis常见阻塞原因

1、命令阻塞 使用时间复杂度O&#xff08;n&#xff09;的不当命令造成全表扫描&#xff0c;导致阻塞 如 keys * 获取所有key 2、RDB持久化save阻塞 Redis提供两个命令来生成RDB快照文件&#xff1a; 1、save&#xff1a;主线程阻塞&#xff0c;写完RDB才放行 2、bgsave : …

qml 实现一个listview

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