Promise 1.Promise基本介紹 Promise是非同步編程的一種解決方案,可以解決傳統Ajax回調函數嵌套問題。 傳統的Ajax非同步調用在需要多個操作的時候,會導致多個回調函數嵌套,導致代碼不夠直觀,就是常說的Callback Hell 為瞭解決上述的問題,Promise對象應運而生,在E ...
Promise
1.Promise基本介紹
Promise是非同步編程的一種解決方案,可以解決傳統Ajax回調函數嵌套問題。
- 傳統的Ajax非同步調用在需要多個操作的時候,會導致多個回調函數嵌套,導致代碼不夠直觀,就是常說的Callback Hell
- 為瞭解決上述的問題,Promise對象應運而生,在EMCAScript 2015當中已經成為標準,Promise也是ES6的新特性
- Promise是非同步編程的一種解決方案
- 從語法上說,Promise是一個對象,從它可以獲取非同步操作的消息
2.Promise應用實例
2.1需求分析/圖解
-
需求:演示promise非同步請求使用
-
執行效果:
2.2代碼實現
使用json文件模擬資料庫表數據
monster.json
{
"id": 1,
"name": "黑山老妖"
}
monster_detail_1.json
{
"id": 1,
"address": "黑山洞",
"skill": "翻江倒海",
"age": 500,
"gfid": 2
}
monster_gf_2.json
{
"name": "狐狸精",
"age": 100
}
2.2.1jquery-ajax實現多次ajax請求
<!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) {//第一次ajax成功的回調函數
console.log("第一次ajax請求 monster 基本信息=", resultData);
//發出第二次ajax請求
$.ajax({
//第二次ajax請求的url根據第一次的結果來改變
url: `data/monster_detail_${resultData.id}.json`,
success(resultData) {//第二次ajax成功的回調函數
console.log("第二次ajax請求 monster 詳細信息=", resultData);
},
error(err) {
console.log("第二次ajax請求出現異常=", err);
}
})
},
error(err) {
console.log("第一次ajax請求出現異常=", err);
}
})
</script>
</head>
<body>
</body>
</html>
使用jquery-ajax的方式容易出現回調函數嵌套(Callback Hell),如果發出的是多次ajax請求,那麼嵌套的層數將會變得非常多,代碼不易讀。這種寫法冗餘度高,代碼可維護性低。
2.2.2promise對象實現多次ajax請求
首先創建一個Promise對象,在該對象內傳入一個箭頭函數,箭頭函數內進行ajax請求。Promise對象的箭頭函數傳入了兩個方法作為參數(命名隨意),這裡的resolve方法是ajax請求成功後調用的函數,reject方法是ajax請求失敗後調用的函數。不同於jquery的回調嵌套,在ajax請求成功的success方法中會調用resolve(),並且把第一次ajax請求獲得的數據傳入該方法。
resolve方法會跳到Promise對象的then()方法,then方法中可以繼續使用$.ajax()去進行第二次ajax請求。在then方法中,又創建了一個Promise對象,該對象和之前的Promise對象中的業務邏輯相似,不同的是可以通過上一次的resolve方法,拿到第一次ajax請求返回的數據,然後根據數據進行第二次的ajax請求.......在第二次的ajax請求中,又可以獲取第二次ajax請求返回的數據,然後調用這次Promise對象的resolve(),將新的數據傳給這次Promise對象的then()方法.....
即,第二次ajax請求的resolve方法又會跳到Promise對象的then()方法........以此類推。
整個過程形成了一個鏈式的調用。
<!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函數
// reject:如果請求失敗,調用reject函數
//4.箭頭函數體內仍然是通過jquery發出ajax
let promise = new Promise((resolve, reject) => {
//發出ajax請求
$.ajax({
url: "data/monster.json",
success(resultData) {//第一次ajax請求成功的回調函數
console.log("Promise發出的第一次ajax請求,返回的monster基本信息=", resultData);
resolve(resultData);
},
error(err) {
//console.log("Promise第一次非同步請求出現異常=", err);
reject(err);
}
})
});
//這裡我們可以繼續編寫第一次請求成功之後的業務
//仍然使用箭頭函數
promise.then((resultData) => {
//這裡可以繼續發出請求
return new Promise((resolve, reject) => {
$.ajax({
url: `data/monster_detail_${resultData.id}.json`,
success(resultData) {//第二次ajax請求成功的回調函數
console.log("Promise發出的第二次ajax請求,返回的monster詳細信息=", resultData);
//可以繼續進行下一次的請求
resolve(resultData);
},
error(err) {
//console.log("Promise第二次非同步請求出現異常=", err);
reject(err);
}
})
})
}).then((resultData) => {
console.log("promise.then().then(),resultDate", resultData);
//這裡可以繼續發出第三次ajax請求....
return new Promise(((resolve, reject) => {
$.ajax({
url: `data/monster_gf_${resultData.gfid}.json`,
success(resultData) {//第二次ajax請求成功的回調函數
console.log("Promise發出的第三次ajax請求,返回的monster gf信息=", resultData);
//可以繼續進行下一次的請求
//resolve(resultDate);
},
error(err) {
//console.log("Promise第三次次非同步請求出現異常=", err);
reject(err);
}
})
}))
}).catch((err) => {//這裡可以對多次ajax請求的異常進行處理
console.log("promise非同步請求異常=", err);
})
</script>
</head>
<body>
</body>
</html>
2.2.3promise代碼重排
雖然在2.2.2中使用promise實現了多次ajax請求,解決了jquery-ajax的嵌套回調問題,但是代碼仍然顯得臃腫。創建Promise對象和進行ajax請求的代碼是重覆的,因此可以進行封裝,代碼重排,增強可讀性。
<!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
//3.再獲取monster_gf_2.json
get("data/monster.json").then((resultData) => {
//第一次ajax請求成功後的處理代碼
console.log("第1次ajax請求返回的數據=", resultData);
return get(`data/monster_detail_${resultData.id}.json`);
}).then((resultData) => {
//第二次ajax請求成功後的處理代碼
console.log("第2次ajax請求返回的數據=", resultData);
return get(`data/monster_gf_${resultData.gfid}.json`);
}).then((resultData) => {
//第三次ajax請求成功後的處理代碼
console.log("第3次ajax請求返回的數據=", resultData);
//如果還有就繼續...
}).catch(err => {
console.log("請求出現異常=", err)
})
</script>
</head>
<body>
</body>
</html>
3.練習
分別使用Jquery-Ajax和Promise代碼重排,完成如下功能,發出3次ajax請求,獲取對應的數據,註意體會Promise發出多次Ajax請求的方便之處。
student_100.json
{
"id": 100,
"name": "jack",
"class_id": 10
}
class_10.json
{
"id": 10,
"name": "java工程師班級",
"student_num": 30,
"school_id": 9
}
school_9.json
{
"id": 9,
"name": "清華大學",
"address": "北京"
}
3.1jquery-ajax方式
<!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請求
$.ajax({
url: "data/student_100.json",
success(resultData) {
console.log("第一次ajax請求=", resultData);
//第二次ajax請求
$.ajax({
url: `data/class_${resultData.class_id}.json`,
success(resultData) {
console.log("第二次ajax請求=", resultData);
//第三次ajax請求
$.ajax({
url: `data/school_${resultData.school_id}.json`,
success(resultData) {
console.log("第三次ajax請求=", resultData);
},
error(err) {
console.log("第三次ajax請求出現異常=", err);
}
})
},
error(err) {
console.log("第二次ajax請求出現異常=", err);
}
})
},
error(err) {
console.log("第一次ajax請求出現異常=", err);
}
})
</script>
</head>
<body>
</body>
</html>
3.2Promise代碼重排
<!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方法也可以封裝到js工具類,重覆使用
function get(url, data) {
return new Promise(((resolve, reject) => {
$.ajax({
url: url,
data: data,
success(resultData) {
resolve(resultData);
},
error(err) {
reject(err);
}
})
}))
}
//業務
get("data/student_100.json").then(resultData => {
console.log("第1次返回的數據=", resultData);
return get(`data/class_${resultData.class_id}.json`);
}).then(resultData => {
console.log("第2次返回的數據=", resultData);
return get(`data/school_${resultData.school_id}.json`);
}).then(resultData => {
console.log("第3次返回的數據=", resultData);
//如有需求可以繼續請求...
}).catch(err => {
console.log("promise非同步請求異常=", err)
})
</script>
</head>
<body>
</body>
</html>