<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>promise學(xué)習(xí)</title>
<!-- 在js中,所有代碼都是單線程執(zhí)行的 -->
<!-- 異步執(zhí)行:可以使用回調(diào),在ES6中我們可以使用Promise對(duì)象來實(shí)現(xiàn) -->
<!--
1.1Promise對(duì)象,只需要then一個(gè)方法,then方法帶有如下三個(gè)參數(shù)
? ? 1.成功回調(diào)
? ? 2.失敗回調(diào)
? ? 3.前進(jìn)回調(diào)(暫時(shí)不講)
? ? 一個(gè)全新的 promise 對(duì)象從每個(gè) then 的調(diào)用中返回。
1.2 Promise對(duì)象代表一個(gè)異步操作,其不受外界影響,有三種狀態(tài)
.Pending進(jìn)行中
.Resolved(已完成,又稱Fulfilled)
.Rejected(已失敗)
1.3使用Promise的優(yōu)勢(shì)
1.3.1 解決回調(diào)地獄問題(Callback Hell)
例如,有時(shí)候我們可能會(huì)進(jìn)行多個(gè)異步操作,后一個(gè)的請(qǐng)求需要上一次請(qǐng)求的返回結(jié)果,所以過去我們都是用callback層層嵌套,
但是多了的話就會(huì)出現(xiàn)回調(diào)地獄,代碼的可讀性和維護(hù)性都會(huì)變得很差
firstAsync(function(data){
? ? ? ? ? ? ? ? ? ? ? ? //處理得到的 data 數(shù)據(jù)
//....
secondAsync(function(data2){
//處理得到的 data2 數(shù)據(jù)
//....
thirdAsync(function(data3){
? //處理得到的 data3 數(shù)據(jù)
? //....
});
});
});
1.3.2 使用promise的話,代碼會(huì)變得扁平和可讀.前面提到了then返回一個(gè)promise,因此我們可以將then的調(diào)用不停的串聯(lián)起來,其中then返回的
promise裝載了由調(diào)用返回的值.
firstAsync()
.then(function(data){
//處理得到的 data 數(shù)據(jù)
//....
return secondAsync();
})
.then(function(data2){
//處理得到的 data2 數(shù)據(jù)
//....
return thirdAsync();
})
.then(function(data3){
//處理得到的 data3 數(shù)據(jù)
//....
});
1.3.3 更好的進(jìn)行錯(cuò)誤捕獲
多層嵌套會(huì)造成無法捕獲異常,使用promise,通過使用reject方法把promise的狀態(tài)設(shè)置為rejected,這樣我們?cè)趖hen中就能捕捉到,然后執(zhí)行失敗情況的回調(diào)
function fetch(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('請(qǐng)求失敗');
}, 2000)
})
}
fetch()
.then(
function(data){
console.log('請(qǐng)求處理');
console.log(data);
},
function(reason, data){
console.log('觸發(fā)異常');
console.log(reason);
}
);
當(dāng)然我們?cè)赾atch方法中處理reject回調(diào)也是可以的,
function fetch(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('請(qǐng)求失敗');
}, 2000)
})
}
fetch()
.then(
function(data){
console.log('請(qǐng)求處理');
console.log(data);
}
)
.catch(function(reason){
console.log('觸發(fā)異常');
console.log(reason);
});
-->
</head>
<body>
<script type="text/javascript">
new Promise(function(resolve, reject) {
console.log('start new Promise...');
var timeOut = Math.random() * 2;
console.log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function() {
if (timeOut < 10) {
console.log('call resolve()...');
resolve('200 OK');
} else {
console.log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}).then(function(r) {
console.log('Done: ' + r);
}).catch(function(reason) {
console.log('Failed: ' + reason);
});
// promise的使用詳解,簡(jiǎn)單來講,then方法就是把原來的回調(diào)寫法分離出來,在異步執(zhí)行操作執(zhí)行完成后,用鏈?zhǔn)秸{(diào)用的方式,回調(diào)函數(shù);
// 我們可以在then方法中繼續(xù)寫promise對(duì)象并返回,然后繼續(xù)調(diào)用then進(jìn)行回調(diào)操作
// then方法舉例? ? ? ? ? 例如 學(xué)習(xí) 考試? 放假
function study() {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("學(xué)習(xí)結(jié)束,開始考試")
}, 2000)
});
return p;
}
function test(data) {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("考試結(jié)束,開始假期")
}, 2000)
});
return p;
}
function holiday(data) {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("假期結(jié)束,開始上課")
}, 2000)
});
return p;
}
// 使用then鏈?zhǔn)秸{(diào)用這三個(gè)方法
study()
.then(function(data) {
console.log(data)
return test(data);
})
.then(function(data) {
console.log(data)
return holiday(data)
})
.then(function(data) {
console.log(data)
})
// 運(yùn)行結(jié)果
// 學(xué)習(xí)結(jié)束,開始考試
// 試結(jié)束,開始假期
// 假期結(jié)束,開始上課
// 2.reject方法
function learn() {
var p = new Promise(function(reslove, reject) {
setTimeout(() => {
reject("考試不及格")
}, 1000)
});
return p;
}
learn()
.then(test, function(data) {
console.log(data + "無法放假,復(fù)習(xí)吧");
})
// 執(zhí)行結(jié)果
// 考試不及格無法放假,復(fù)習(xí)吧
// 另外如果我們只要處理失敗的情況,可以使用then(null,.....),或者使用catch方法
learn()
.then(null, function(data) {
console.log(data + "無法放假,復(fù)習(xí)吧");
})
// catch方法和then方法的第二個(gè)參數(shù)一樣,用來指定reject的回調(diào)
learn()
.then(test)
.catch(function(data) {
console.log("沒得玩了");
})
// 另一個(gè)作用是,當(dāng)執(zhí)行resolve的回調(diào)時(shí),如果拋出了異常(代碼出錯(cuò)),那么也不會(huì)報(bào)錯(cuò)卡死js,而是會(huì)進(jìn)到這個(gè)catch中
study()
.then(function(data) {
throw new Error("考題泄漏");
test(data)
})
.catch(function(data) {
console.log(data + "無法繼續(xù)考試")
})
// all方法,提供了并行異步執(zhí)行操作的能力,并且在所有異步操作執(zhí)行完后才會(huì)執(zhí)行回調(diào)
// 例如放假要等到學(xué)習(xí)和考試之后
setTimeout(() => {
Promise.all([study(), test(),holiday()])
.then(function(data) {
console.log("開始放假了:后面的是data數(shù)據(jù)? "+data.length+"第一個(gè):"+data[0]+"第二個(gè):"+data[1]+"第三個(gè):"+data[2])
// 打印結(jié)果:? 開始放假了:后面的是data數(shù)據(jù)? 3第一個(gè):學(xué)習(xí)結(jié)束,開始考試第二個(gè):考試結(jié)束,開始假期第三個(gè):假期結(jié)束,開始上課
})
}, 1000)
// race方法,用法與all一樣,只是all是等所有的異步操作完成之后,才會(huì)執(zhí)行then回調(diào).而race回調(diào)的話只要有一個(gè)異步操作執(zhí)行完畢,就立刻執(zhí)行then回調(diào);
//then方法里面的回調(diào)中的參數(shù)data是一個(gè)數(shù)組,我們可以得到異步執(zhí)行操作的結(jié)果
// PS:其他沒有執(zhí)行完畢的異步操作,仍然會(huì)繼續(xù)執(zhí)行,而不是停止
setTimeout(() => {
Promise.race([study(), test()])
.then(function(data) {
console.log("考試不考試,學(xué)習(xí)不學(xué)習(xí),都沒關(guān)系的")
})
}, 20000)
// race的使用場(chǎng)景很多,例如我們可以給某一個(gè)race設(shè)置請(qǐng)求超時(shí)時(shí)間
//考研開始,5s內(nèi)交卷認(rèn)為合格,否則認(rèn)為不合格
function passTheExam() {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("交卷")
}, 25000);
})
return p;
}
function requestTimeOut() {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
reject("考試失敗")
}, 30000);
})
return p;
}
Promise.race([passTheExam(),requestTimeOut()])
.then(function(data){
console.log(data);
})
.catch(function(err){
console.log(err);
})
</script>
</body>
</html>