AJAX-Promise 详解

news2024/12/23 19:08:39

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)

目录

前言

一、Promise基本概念

1.1 定义

1.2 状态

1.3 构造函数

二、Promise基本用法

2.1 then()

2.2 catch()

2.3 链式调用

三、Promise高级特性

3.1 Promise.all()

3.2 Promise.allSettled()

3.3 Promise.race()

3.4Promise.any()

四. Promise的调试与优化

4.1 使用async/await

4.2 错误处理

4.3 并行执行

4.4 性能优化

五. 结论


前言

在JavaScript的异步编程世界中,Promise无疑是一个里程碑式的存在。它提供了一种更加优雅和强大的方式来处理异步操作,解决了传统回调函数的“回调地狱”问题,使得代码更加清晰、易于维护。本文将深入探索Promise的各个方面,包括其基本概念、基本用法、链式调用、错误处理、静态方法、与async/await的结合使用,以及在实际项目中的应用。

一、Promise基本概念

1.1 定义

Promise是JavaScript中的一个对象,它代表了一个尚未完成但预期将来会完成的异步操作的结果。它允许你为异步操作的成功(fulfilled)和失败(rejected)注册回调函数。

1.2 状态

Promise有三种状态:

  • Pending(等待中):初始状态,既不是成功,也不是失败状态。
  • Fulfilled(已成功):意味着操作成功完成。
  • Rejected(已失败):意味着操作失败。

一旦Promise被fulfilled或rejected,它的状态就不能再改变。

1.3 构造函数

Promise的构造函数接收一个执行器(executor)函数作为参数,该执行器函数本身又接收两个函数作为参数:resolve和reject。

let promise = new Promise(function(resolve, reject) {  
  // 异步操作  
  if (/* 异步操作成功 */) {  
    resolve(value); // 将Promise的状态从"pending"变为"fulfilled",并将value作为操作成功的结果  
  } else {  
    reject(error); // 将Promise的状态从"pending"变为"rejected",并将error作为操作失败的原因  
  }  
});

二、Promise基本用法

2.1 then()

then()方法用于指定Promise成功时(即fulfilled时)的回调函数,并返回一个新的Promise实例。

promise.then(function(value) {  
  // 当Promise成功时执行  
  console.log(value);  
}, function(error) {  
  // 可选:当Promise失败时执行(但通常不推荐这种方式,因为会破坏链式调用)  
  console.error(error);  
});

2.2 catch()

catch()方法是.then(null, rejection)的语法糖,用于指定Promise失败时(即rejected时)的回调函数。

promise.then(function(value) {  
  // 成功时执行  
}).catch(function(error) {  
  // 失败时执行  
  console.error(error);  
});

2.3 链式调用

Promise支持链式调用,因为then()catch()方法都会返回一个新的Promise实例。

fetch('https://api.example.com/data')  
  .then(response => response.json())  
  .then(data => {  
    console.log(data);  
  })  
  .catch(error => {  
    console.error('Fetch error:', error);  
  });

三、Promise高级特性

3.1 Promise.all()

Promise.all()方法接收一个Promise对象的数组作为参数,并返回一个新的Promise实例。只有当数组中的所有Promise都被fulfilled时,返回的Promise才会被fulfilled,其结果是一个包含所有fulfilled值的数组。

let promise1 = Promise.resolve(3);  
let promise2 = 42;  
let promise3 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));  
  
Promise.all([promise1, promise2, promise3]).then(values => {  
  console.log(values); // [3, 42, "foo"]  
});

3.2 Promise.allSettled()

Promise.allSettled()是ES2020中引入的一个新方法,它类似于Promise.all(),但不同之处在于它等待所有给定的Promise都完成(无论是fulfilled还是rejected),并返回一个数组,数组中的每个元素都是一个对象,描述了对应Promise的结果。

const promise1 = Promise.resolve(3);  
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 50, 'rejection'));  
const promise3 = new Promise((resolve) => setTimeout(resolve, 100, 'foo'));  
  
Promise.allSettled([promise1, promise2, promise3]).then((results) => {  
  results.forEach((result) => {  
    if (result.status === 'fulfilled') {  
      console.log('fulfilled:', result.value);  
    } else if (result.status === 'rejected') {  
      console.log('rejected:', result.reason);  
    }  
  });  
  // 输出:  
  // fulfilled: 3  
  // rejected: rejection  
  // fulfilled: foo  
});

3.3 Promise.race()

Promise.race()方法返回一个新的Promise,该Promise以输入数组中第一个解决(无论是fulfilled还是rejected)的Promise的结果作为自己的结果。这在处理具有超时限制或需要快速响应的场景时非常有用。

const fastPromise = new Promise((resolve) => setTimeout(resolve, 100, 'Fast one won'));  
const slowPromise = new Promise((resolve) => setTimeout(resolve, 500, 'But I am here too'));  
  
Promise.race([fastPromise, slowPromise]).then((value) => {  
  console.log(value); // 输出: Fast one won  
}).catch((error) => {  
  console.error('An error occurred', error);  
});

3.4Promise.any()

Promise.any()是ES2020中引入的另一个静态方法,它返回一个新的Promise,该Promise以输入数组中第一个成功(fulfilled)的Promise的结果作为自己的结果。如果所有输入的Promise都失败了,则返回的Promise将拒绝(reject),并抛出一个AggregateError,表示所有Promise都失败了。

const promise1 = new Promise((resolve, reject) => setTimeout(reject, 500, 'First failed'));  
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'Second succeeded'));  
const promise3 = new Promise((resolve, reject) => setTimeout(reject, 150, 'Third failed'));  
  
Promise.any([promise1, promise2, promise3]).then((value) => {  
  console.log(value); // 输出: Second succeeded  
}).catch((errors) => {  
  console.error('All promises failed', errors);  
  // 在这个例子中,这个catch块不会被执行  
});

四. Promise的调试与优化

在使用Promise进行异步编程时,合理的调试和优化是提高代码质量和性能的关键。以下是一些建议:

  • 使用浏览器的开发者工具:利用浏览器的网络监控、断点调试等功能来跟踪Promise的状态和值。
  • 避免创建不必要的Promise链:保持Promise链的简洁性,避免过长的链式调用,以减少回调地狱(Callback Hell)的发生。
  • 利用async/await简化异步代码async/await是JavaScript中处理异步操作的现代、更简洁的语法糖,它们基于Promise构建,可以让异步代码看起来和同步代码一样。以下是如何利用async/await来进一步简化和优化Promise的使用。

4.1 使用async/await

async关键字用于声明一个异步函数,该函数会隐式地返回一个Promise。在async函数内部,你可以使用await关键字来等待一个Promise解决,而无需显式地编写.then().catch()链。

async function fetchData() {  
  try {  
    const response = await fetch('https://api.example.com/data');  
    const data = await response.json();  
    console.log(data);  
  } catch (error) {  
    console.error('Failed to fetch data:', error);  
  }  
}  
  
fetchData();

在这个例子中,fetchData函数是异步的,它使用await来等待fetch调用和JSON解析的结果。如果任何一个await表达式失败,控制流将跳转到catch块。

4.2 错误处理

在使用async/await时,错误处理变得非常直观。你可以使用标准的try...catch语句来捕获和处理异步操作中发生的错误。

async function fetchAndProcessData() {  
  try {  
    const data = await fetchData(); // 假设fetchData是一个返回Promise的异步函数  
    // 处理数据  
  } catch (error) {  
    console.error('Error processing data:', error);  
  }  
}

4.3 并行执行

虽然async/await使代码看起来像是同步的,但你不应该用它来并行执行多个异步操作。对于这种情况,你应该使用Promise.all()或其他并行执行的方法,然后在async函数中使用await等待所有操作完成。

async function fetchMultipleData() {  
  const promises = [  
    fetch('https://api.example.com/data1'),  
    fetch('https://api.example.com/data2')  
  ];  
  
  const [response1, response2] = await Promise.all(promises);  
  const [data1, data2] = await Promise.all([response1.json(), response2.json()]);  
  
  console.log(data1, data2);  
}  
  
fetchMultipleData();

4.4 性能优化

  • 避免不必要的等待:不要在没有必要时使用await,特别是在循环或频繁调用的函数中。
  • 使用缓存:对于重复请求相同资源的情况,考虑使用缓存来避免不必要的网络请求。
  • 限制并发请求:如果你的应用需要发送大量并发请求,考虑限制同时进行的请求数量,以避免资源耗尽。

五. 结论

Promise是JavaScript中处理异步操作的重要工具,而async/await则为它们的使用提供了更简洁、更直观的语法。通过合理使用Promise的高级特性和async/await,你可以编写出既清晰又高效的异步代码。然而,重要的是要记住,异步编程的本质并未改变,只是工具和语法变得更加方便和强大。因此,理解和掌握异步编程的基本概念仍然是至关重要的。

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

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

相关文章

ThinkPHP一对一关联模型的运用(ORM)

一、序言 最近在写ThinkPHP关联模型的时候一些用法总忘,我就想通过写博客的方式复习和整理下一些用法。 具体版本: topthink/framework:6.1.4topthink/think-orm:2.0.61 二、实例应用 1、一对一关联 1.1、我先设计了两张表&#x…

根据题意写出完整的css,html和js代码【购物车模块页面及功能实现】

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 问题描述 根据题意写出完…

基于微信小程序+SpringBoot+Vue的社区超市管理系统(带1w+文档)

基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 为了让商品信息的管理模式进行升级,也为了更好的维护商品信息,社区超市管理系统的开发运用就显得很有必要,因为它不仅可…

C# 植物大战僵尸

Winform 版本开发 高效率、流畅植物大战僵尸 git地址:冯腾飞/植物大战僵尸

go语言day19 使用git上传包文件到github Gin框架入门

git分布式版本控制系统_git切换head指针-CSDN博客 获取请求参数并和struct结构体绑定_哔哩哔哩_bilibili (gin框架) GO: 引入GIn框架_go 引入 gin-CSDN博客 使用git上传包文件 1)创建一个github账户,进入Repositories个人仓…

我在百科荣创企业实践——简易函数信号发生器(6)

对于高职教师来说,必不可少的一个任务就是参加企业实践。这个暑假,本人也没闲着,报名参加了上海市电子信息类教师企业实践。7月8日到13日,有幸来到美丽的泉城济南,远离了上海的酷暑,走进了百科荣创科技发展有限公司。在这短短的一周时间里,我结合自己的教学经验和企业的…

buu做题(8)

[安洵杯 2019]easy_web 查看源代码可以发现一长串的base64编码 就是页面上的一张图片 回到原页面,url上面也有一些奇怪的参数 经过两次base64和一次hex 解密后得到 555.png 应该就是包含着页面上的这张图片 然后尝试将index.php 按照这样的方式编码, 看看能不能包含到 TmprMl…

后端解决跨域(Cross-Origin Resource Sharing)(三种方式)

注解CrossOrigin 控制层的类上或者方法上加注解CrossOrigin 实现接口并重写方法 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**&qu…

算法通关:006_4二分查找:寻找数组中的峰值

文章目录 描述主要代码全部代码运行结果总结 二分法不一定只能用在有序数组中。 描述 leetcode:162 主要代码 //二分法查找峰值public static int findPeakElement(int[] arr){if (arr.length 1){//randomArray()不会出现arr null的情况return 0;}//先检查 0…

LabVIEW操作系列1

系列文章目录 我的记录: LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…

二叉树以及堆的实现

树 树的定义及概念 树是⼀种非线性的数据结构,它是由n(n>0) 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有⼀个特殊的结点,称…

[Meachines] [Easy] Admirer Adminer远程Mysql反向+Python三方库函数劫持权限提升

信息收集 IP AddressOpening Ports10.10.10.187TCP:21,22,80 $ nmap -p- 10.10.10.187 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.4p1 Debian 10deb9u7 (protocol 2.0) | ssh-hostkey: | …

Redis:十大数据类型

键(key) 常用命令 1. 字符串(String) 1.1 基本命令 set key value 如下:设置kv键值对,存货时长为30秒 get key mset key value [key value ...]mget key [key ...] 同时设置或者获取多个键值对 getrange…

万物互联,触手可及“2024南京智慧城市,物联网,大数据展会”

在金秋送爽的11月,南京这座历史悠久而又充满活力的城市,即将迎来一场科技盛宴——2024南京智慧城市、物联网、大数据展会。这不仅是一场技术的集会,更是未来生活蓝图的预览,它汇聚了全球顶尖的科技企业、创新者及行业精英&#xf…

制作PE启动U盘 预防电脑无法正常开机进入系统

PE 是一种简化版的便携式操作系统,它可以直接装载在 U 盘里运行。通过它我们能做非常多的应急操作,比如删除文件、卸载软件、拷贝数据、格式化硬盘、重装系统等。 在电脑无法正常开机进入系统,身边又没有其他电脑时,手头有个 PE …

Corsearch 用 ClickHouse 替换 MySQL 进行内容和品牌保护

本文字数:3357;估计阅读时间:9 分钟 作者:ClickHouse Team 本文在公众号【ClickHouseInc】首发 Chase Richards 自 2011 年在初创公司 Marketly 担任工程负责人,直到 2020 年公司被收购。他现在是品牌保护公司 Corsear…

【Linux】-----工具篇(编译器gcc/g++,调试器gdb)

目录 一、gcc/g 简单认识 程序的翻译过程认识gcc 预处理(宏替换) 编译 汇编 链接 宏观认识 如何理解(核心) 什么是链接? 链接的分类 二、gdb 基本的认识 基本操作及指令 安装gdb 启动gdb ​编辑 显示源代码(list) 运行程序…

网友提问:桌面与web开发哪个难度更大?

关于桌面应用开发与Web开发哪个难度更大的问题,实际上并没有绝对的答案,因为这取决于具体的开发任务、所使用的工具和技术栈等因素。不过,我们可以从几个方面来进行比较: 技术栈 Web开发: 前端通常涉及到HTML、CSS、J…

Ansible之playbook剧本编写(二)

tags 模块 可以在一个playbook中为某个或某些任务定义“标签”,在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。 playbook还提供了一个特殊的tags为always。作用就是当使用always作为tags的task时,无论执行哪一个t…

全球奈拉滨市场规模预测:未来六年年复合增长率CAGR为1.1%

据恒州诚思研究,2023年全球奈拉滨市场规模大约为3.8亿元,预计未来六年年复合增长率CAGR为1.1%,到2030年市场规模将接近4.2亿元。这一增长反映了奈拉滨在全球医药行业中的重要性及其在未来发展中的潜在机会。随着科学的进一步发展和市场的扩展…