ES6 Promise的理解應用
阿新 • • 發佈:2020-12-29
技術標籤:JSjavascriptes6前端
本文是讀了阮一峰大神《ES6標準入門》-Promise 物件 後的一些個人的小總結
1. 什麼是promise?
1.1 重要概念
一個 Promise 必然處於以下幾種狀態之一:
- 待定(pending): 初始狀態,既沒有被兌現,也沒有被拒絕。
- 已兌現(fulfilled): 操作成功完成。
- 已拒絕(rejected): 操作失敗。
待定狀態的 Promise 物件要麼會通過一個值被兌現(fulfilled),要麼會通過一個原因(錯誤)被拒絕(rejected)。
1.2 建立promise
- promise物件是一個建構函式,用來生成promise例項
- 該建構函式會把一個叫做“處理器函式”(executor function)的函式作為它的引數。這個“處理器函式”接受兩個函式resolve 和 reject 作為其引數。
- 當非同步任務順利完成且返回結果值時,會呼叫 resolve 函式;而當非同步任務失敗且返回失敗原因(通常是一個錯誤物件)時,會呼叫reject 函式。
- resolve:pending ——> resolved, 非同步操作的結果作為返回值
- reject:pending ——> rejected, 錯誤原因作為返回值
- promise例項生成以後,用 then 方法指定resolved狀態和rejected狀態的回撥函式
注:為了方便,resolved(表示 promise 已經處於已敲定(settled)狀態)指fulfilled狀態。
const promise = new Promise(function(resolve,reject){
// some codes
if(/*非同步操作成功*/){
resolve(value);
}else{
reject(error);
}
});
//then方法接受兩個回撥函式作為引數,第二個函式不一定提供
promise.then(function(value){
//suc
},function(error){
//fail
});
舉一個栗子:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done'); //done是resolve函式的引數,這裡就是value
});
}
timeout(3000).then((value) => {
console.log(value);
});
上面栗子是說,過了指定時間(本例3000ms)後promise例項的狀態變成resolved,觸發then方法的回撥函式打印出結果(done)
2. promise的執行順序
- promise新建後立即執行
- then方法指定的回撥函式,在當前指令碼所有同步任務執行完成後才執行
直接來看栗子叭~~
console.log('Hi!');
let promise = new Promise(function(resolve, reject) {
console.log('I am Promise'); //新建後立即執行
resolve();
});
console.log("I'm tom");
promise.then(function() {
console.log('resolved.'); //在當前指令碼所有同步任務執行完成後才執行
});
console.log("I'm a boy");
結果如下:
3. 使用promise可以避免回撥地獄
初次學習promise的時候,老師說promise可以避免回撥地獄。腦子裡面一直似懂非懂的,這下終於弄懂了來記錄一下。
再舉個栗子~~
我們現在想模擬一下接力跑的過程,我們如何用程式碼實現呢?
function f1(next){
console.log("f1起跑...");
setTimeout(()=>{
console.log("f1到達,傳遞接力棒");
next();
},4000)
}
function f2(next){
console.log("f2起跑...");
setTimeout(()=>{
console.log("f2到達,傳遞接力棒");
next();
},5000)
}
function f3(next){
console.log("f3起跑...");
setTimeout(()=>{
console.log("f3到達終點");
next();
},3000)
}
f1(function(){
f2(function(){
f3(function(){
console.log("比賽結束!");
})
})
})
通過上面程式碼,我們的確得到了預期的結果:
我們難以想象如果有更多的層層巢狀的回撥函式,我們還能這樣的輕鬆的、不出錯的寫出程式碼嗎?
這樣的程式碼可讀性低、編寫費勁、容易出錯,我們該如何解決呢?
來看看用promise如何解決:
function f1(next){
return new Promise(function(resolve,reject){
console.log("f1起跑...");
setTimeout(()=>{
console.log("f1到達,傳遞接力棒");
resolve();
},4000)
})
}
function f2(next){
return new Promise(function(resolve,reject){
console.log("f2起跑...");
setTimeout(()=>{
console.log("f2到達,傳遞接力棒");
resolve();
},5000)
})
}
function f3(next){
return new Promise(function(resolve,reject){
console.log("f3起跑...");
setTimeout(()=>{
console.log("f3到達終點");
resolve();
},3000)
})
}
f1()
.then(f2)
.then(f3)
.then(()=>console.log("比賽結束!"));
總結:
- 使用then方法依次指定多個回撥函式
- 第一個回撥函式完成後,會將結果作為引數傳入第二個回撥函式
- 採用鏈式的then,可以指定一組按照次序呼叫的回撥函式。若第一個回撥函式返回一個promise物件,這時後面的回撥函式會等待該promise物件狀態發生變化,才會被呼叫
還有一些promise的靜態方法沒有總結,下次補上~