Promise
Promise 基本介绍
1. 传统的 Ajax 异步调用在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的 Callback Hell
2. 为了解决上述的问题,Promise 对象应运而生,在 EMCAScript 2015 当中已经成为标准
3. Promise 是异步编程的一种解决方案。
4. 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息
5. Promise 也是 ES6 的新特性,因为比较重要,老师单独拉出来讲
一句话: Promise 是异步编程的一种解决方案, 可以解决传统 Ajax 回调函数嵌套问题
Promise 应用实例
需求: 演示 promise 异步请求使用(如图)
代码实现
monster.json
{
"id": 1,
"name": "黑山老妖"
}
monster_detail_1.json
{
"address": "阴曹地府-黑山",
"skill": "翻江倒海功",
"age": 800
}
先使用 ajax 传统方式完成, 问题分析(出现回调函数嵌套)
ajax.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jquery-ajax多次请求</title> <!--引入jquery--> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <script type="text/javascript"> //jquery发出ajax的方式-回顾 $.ajax({ url: "data/monster.json", success(resultData) {//如果请求成功了,回调处理函数success console.log("第1次ajax请求 monster基本信息=", resultData); //发出第二次ajax请求 $.ajax({ url: `data/monster_detail_${resultData.id}.json`, //下面是es6对象的方法简写形式 success(resultData) { console.log("第2次ajax请求 monster详细信息=", resultData); //$.ajax => callback hell //$.ajax //$.ajax }, error(err) { //出错的回调函数 console.log("出现异常=", err); } }) }, error(err) { console.log("出现异常=", err); } }) </script> </head> <body> </body> </html>
使用 promise 方式
promise.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>使用promise完成多次ajax请求</title> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <script type="text/javascript"> //先请求到monster.json //解读 //1. 创建Promise对象 //2. 构造函数传入一个箭头函数 //3. (resolve, reject) 参数列表resolve: 如果请求成功, 调用resolve函数 //4. 如果请求失败, 调用reject函数 //5. 箭头函数体, 仍然是通过jquery发出ajax let p = new Promise((resolve, reject) => { //发出ajax $.ajax({ url: "data/monster.json", success(resultData) {//成功的回调函数 console.log("promise发出的第1次ajax monster基本信息=", resultData); resolve(resultData); }, error(err) { //console.log("promise 1发出的异步请求异常=", err); reject(err); } }) }) //这里我们可以继续编写请求成功后的业务 p.then((resultData) => { //这里我们可以继续发出请求 //console.log("p.then 得到 resultData", resultData); return new Promise((resolve, reject) => { $.ajax({ url: `data/monster_detail_${resultData.id}.json`, success(resultData) { //第2次ajax请求成功,回调函数 console.log("第2次ajax请求 monster的详细信息=", resultData); //继续进行下一次的请求 resolve(resultData); }, error(err) { //第2次ajax请求失败,回调函数 //console.log("promise2 发出的异步请求异常=", err); reject(err); } }) }) }).then((resultData) => { console.log("p.then().then(), resultData", resultData) //即可以在这里发出第3次ajax请求=》 获取该妖怪的女友 return new Promise((resolve, reject) => { $.ajax({ url: `data/monster_gf_${resultData.gfid}.json`, success(resultData) { //第3次ajax请求成功,回调函数 console.log("第3次ajax请求 monster女友的详细信息=", resultData); //继续进行下一次的请求 //resolve(resultData); }, error(err) { //第2次ajax请求失败,回调函数 //console.log("promise2 发出的异步请求异常=", err); //reject(err); } }) }) }).catch((err) => { //这里可以对多次ajax请求的异常进行处理 console.log("promise异步请求异常=", err); }) </script> </head> <body> </body> </html>
示意图:
使用 promise 代码优化/重排 方式完成
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>promise代码重排</title> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <script type="text/javascript"> /** * 这里我们将重复的代码,抽出来,编写一个方法get * * @param url ajax请求的资源 * @param data ajax请求携带的数据 * @returns {Promise<unknown>} */ function get(url, data) { return new Promise((resolve, reject) => { $.ajax({ url: url, data: data, success(resultData) { resolve(resultData); }, error(err) { reject(err); } } ) }) } //需求: 完成 //1. 先获取monster.json //2. 获取monster_detail_1.json //2. 获取monster_gf_2.json get("data/monster.json").then((resultData) => { //第1次ajax请求成功后的处理代码 console.log("第1次ajax请求返回数据=", resultData); return get(`data/monster_detail_${resultData.id}.json`); }).then((resultData) => { //第2次ajax请求成功后的处理代码 console.log("第2次ajax请求返回数据=", resultData); //return get(`data/monster_detail_${resultData.id}.json`); return get(`data/monster_gf_${resultData.gfid}.json`); }).then((resultData) => { //第3次ajax请求成功后的处理代码 console.log("第3次ajax请求返回数据=", resultData); //继续.. }).catch((err) => { console.log("promise请求异常=", err); }) </script> </head> <body> </body> </html>
get.js方法
/** * 这里我们将重复的代码,抽出来,编写一个方法get * * @param url ajax请求的资源 * @param data ajax请求携带的数据 * @returns {Promise<unknown>} */ function get(url, data) { return new Promise((resolve, reject) => { $.ajax({ url: url, data: data, success(resultData) { resolve(resultData); }, error(err) { reject(err); } } ) }) }
注意事项和使用细节
1 如果返回的是 Promise 对象,可以继续执行.then()
2 .then((data)=>{}) 的 data 数据是上一次正确执行后 resolve(data) 返回传入的
3 通过多级 .then() 可以对异步请求分层次请求,实现代码重排,代码逻辑更加清晰合理
4 通过多级 .then() 后面的 .catch((err) => {}) 可捕获发生异常,便于调试
综合代码
1. 分别使用 Jquery-Ajax 和 Promise 代码重排 完成如下功能, 发出 3 次 ajax 请求, 获取对应的数据, 注意体会 Promise 发出多次 Ajax 请求的方便之处
student.json
{
"id": 100,
"name": "xxx",
"class_id": 12
}
class_12.json
{
"id": 12,
"name": "java",
"student_num": 30,
"school_id": 9
}
school_9.json
{
"id": 9,
"name": "清华大学",
"address": "北京"
}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jquery-ajax</title> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <script type="text/javascript"> //思路 $.ajax({ url: "data/student.json", success(data) { console.log("第一次ajax请求数据=", data); $.ajax({ url: `data/class_${data.class_id}.json`, success(data) { console.log("第2次ajax请求数据=", data); $.ajax({ url: `data/school_${data.school_id}.json`, success(data) { console.log("第3次ajax请求数据=", data); }, error(err) { console.log("ajax请求发生异常:", err) } }) }, error(err) { console.log("ajax请求发生异常:", err) } }) }, error(err) { console.log("ajax请求发生异常:", err) } }) </script> </head> <body> </body> </html>
promise代码重排完成多次ajax请求
其中里面的get方法前面有代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>promise代码重排完成多次ajax请求</title> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <script type="text/javascript" src="script/promise_utils.js"></script> <script type="text/javascript"> //promise代码重排,完成多次ajax请求 get("data/student_100.json").then(data => { console.log("第1次ajax请求, 返回的数据=", data); return get(`data/class_${data.class_id}.json`); }).then(data => { console.log("第2次ajax请求, 返回的数据=", data); return get(`data/school_${data.school_id}.json`); }).then(data => { console.log("第3次ajax请求, 返回的数据=", data); }).catch(err => { console.log("promise异步请求异常=", err); }) </script> </head> <body> </body> </html>