<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>promise學習</title>
<!-- 在js中,所有程式碼都是單執行緒執行的 -->
<!-- 非同步執行:可以使用回撥,在ES6中我們可以使用Promise物件來實現 -->
<!--
1.1Promise物件,只需要then一個方法,then方法帶有如下三個引數
1.成功回撥
2.失敗回撥
3.前進回撥(暫時不講)
一個全新的 promise 物件從每個 then 的呼叫中返回。
1.2 Promise物件代表一個非同步操作,其不受外界影響,有三種狀態
.Pending進行中
.Resolved(已完成,又稱Fulfilled)
.Rejected(已失敗)
1.3使用Promise的優勢
1.3.1 解決回撥地獄問題(Callback Hell)
例如,有時候我們可能會進行多個非同步操作,後一個的請求需要上一次請求的返回結果,所以過去我們都是用callback層層巢狀,
但是多了的話就會出現回撥地獄,程式碼的可讀性和維護性都會變得很差
firstAsync(function(data){
//處理得到的 data 資料
//....
secondAsync(function(data2){
//處理得到的 data2 資料
//....
thirdAsync(function(data3){
//處理得到的 data3 資料
//....
});
});
});
1.3.2 使用promise的話,程式碼會變得扁平和可讀.前面提到了then返回一個promise,因此我們可以將then的呼叫不停的串聯起來,其中then返回的
promise裝載了由呼叫返回的值.
firstAsync()
.then(function(data){
//處理得到的 data 資料
//....
return secondAsync();
})
.then(function(data2){
//處理得到的 data2 資料
//....
return thirdAsync();
})
.then(function(data3){
//處理得到的 data3 資料
//....
});
1.3.3 更好的進行錯誤捕獲
多層巢狀會造成無法捕獲異常,使用promise,通過使用reject方法把promise的狀態設定為rejected,這樣我們在then中就能捕捉到,然後執行失敗情況的回撥
function fetch(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('請求失敗');
}, 2000)
})
}
fetch()
.then(
function(data){
console.log('請求處理');
console.log(data);
},
function(reason, data){
console.log('觸發異常');
console.log(reason);
}
);
當然我們在catch方法中處理reject回撥也是可以的,
function fetch(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('請求失敗');
}, 2000)
})
}
fetch()
.then(
function(data){
console.log('請求處理');
console.log(data);
}
)
.catch(function(reason){
console.log('觸發異常');
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的使用詳解,簡單來講,then方法就是把原來的回撥寫法分離出來,在非同步執行操作執行完成後,用鏈式呼叫的方式,回撥函式;
// 我們可以在then方法中繼續寫promise物件並返回,然後繼續呼叫then進行回撥操作
// then方法舉例 例如 學習 考試 放假
function study() {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("學習結束,開始考試")
}, 2000)
});
return p;
}
function test(data) {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("考試結束,開始假期")
}, 2000)
});
return p;
}
function holiday(data) {
var p = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("假期結束,開始上課")
}, 2000)
});
return p;
}
// 使用then鏈式呼叫這三個方法
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)
})
// 執行結果
// 學習結束,開始考試
// 試結束,開始假期
// 假期結束,開始上課
// 2.reject方法
function learn() {
var p = new Promise(function(reslove, reject) {
setTimeout(() => {
reject("考試不及格")
}, 1000)
});
return p;
}
learn()
.then(test, function(data) {
console.log(data + "無法放假,複習吧");
})
// 執行結果
// 考試不及格無法放假,複習吧
// 另外如果我們只要處理失敗的情況,可以使用then(null,.....),或者使用catch方法
learn()
.then(null, function(data) {
console.log(data + "無法放假,複習吧");
})
// catch方法和then方法的第二個引數一樣,用來指定reject的回撥
learn()
.then(test)
.catch(function(data) {
console.log("沒得玩了");
})
// 另一個作用是,當執行resolve的回撥時,如果丟擲了異常(程式碼出錯),那麼也不會報錯卡死js,而是會進到這個catch中
study()
.then(function(data) {
throw new Error("考題洩漏");
test(data)
})
.catch(function(data) {
console.log(data + "無法繼續考試")
})
// all方法,提供了並行非同步執行操作的能力,並且在所有非同步操作執行完後才會執行回撥
// 例如放假要等到學習和考試之後
setTimeout(() => {
Promise.all([study(), test(),holiday()])
.then(function(data) {
console.log("開始放假了:後面的是data資料 "+data.length+"第一個:"+data[0]+"第二個:"+data[1]+"第三個:"+data[2])
// 列印結果: 開始放假了:後面的是data資料 3第一個:學習結束,開始考試第二個:考試結束,開始假期第三個:假期結束,開始上課
})
}, 1000)
// race方法,用法與all一樣,只是all是等所有的非同步操作完成之後,才會執行then回撥.而race回撥的話只要有一個非同步操作執行完畢,就立刻執行then回撥;
//then方法裡面的回撥中的引數data是一個陣列,我們可以得到非同步執行操作的結果
// PS:其他沒有執行完畢的非同步操作,仍然會繼續執行,而不是停止
setTimeout(() => {
Promise.race([study(), test()])
.then(function(data) {
console.log("考試不考試,學習不學習,都沒關係的")
})
}, 20000)
// race的使用場景很多,例如我們可以給某一個race設定請求超時時間
//考研開始,5s內交卷認為合格,否則認為不合格
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>
複製程式碼