一:什麼是promise
Promise 是異步程式設計的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。Promise對象是一個代理對象,一個代表未知傳回結果的對象值。這個值在Promise對象建立時可能是未知的,它允許你為異步操作的成功和失敗分别綁定相應的處理方法, 這讓異步方法可以像同步方法那樣傳回值,但并不是立即傳回最終執行結果,而是傳回一個能代表未來出現的結果的promise對象,看起來很抽象,還是用執行個體來了解吧!
二:狀态
pending:初始狀态
fulfilled:成功狀态
rejected:失敗狀态
1、fulfilled、rejected被統稱為settled,fulfilled也可被稱為resolved即為正确時走的狀态
2、隻有兩種狀态變化過程:pending → fulfilled,pending → rejected,且狀态隻可變化一次,一旦發生變化便會一直保持這個結果。
三、使用
new Promise(executor)
executor:一個帶有兩個參數(resolve和reject)的方法,resolve為fulfilled狀态,即成功之後調用,reject為rejected狀态,即失敗之後調用。
即:new Promise(function(resolve, reject){})
1、executor在建立Promise對象時立即調用
2、若executor函數中抛出錯誤,promise狀态為rejected,executor函數傳回值被忽略
先 new一個Promise,示例如下:
let p = new Promise(function (resolve, reject) {
//做一些異步操作
setTimeout(function () {
console.log('執行完成Promise');
resolve('要傳回的資料可以任何資料例如接口傳回資料');
}, 2000);
});
重新整理頁面會發現過了2秒控制台直接打出:
執行完成Promise
其執行過程是:執行了一個異步操作,也就是setTimeout,2秒後,輸出“執行完成”,并且調用resolve方法。在随後介紹的then方法中,可擷取resolve方法所傳回的值。
注意!我隻是new了一個對象,并沒有調用它,我們傳進去的函數就已經執行了,可放在方法中需要的時候進行調用如下所示:
onclickPromise:function(){
console.log('放在方法中被調用')
let p = new Promise(function (resolve, reject) {
//做一些異步操作
setTimeout(function () {
console.log('執行完成Promise');
resolve('要傳回的資料可以任何資料例如接口傳回資料');
}, 2000);
});
return p;
}
調用為:
this.onclickPromise();
四:方法
1、Promise.then(resolve[, reject])
resolve為成功回調函數,reject為失敗回調函數(可選),參數為Promise執行個體傳回值
promiseClick: function (num){
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('數值:', num)
if (num <= 10) {
resolve(num);
}
else {
reject('數字大于10了即将執行失敗回調');
}
}, 2000);
})
return p
}
調用then的例子如下:
this.promiseClick(4).then(
function (data) {
console.log('resolved成功回調');
console.log('成功回調接受的值:', data);
},
function (reason, data) {
console.log('rejected失敗回調');
console.log('失敗執行回調抛出失敗原因:', reason);
console.log('失敗執行回調data是什麼:', data);
}
);
當傳入的值為4時,執行正确操作,調用resolve方法:
數值: 4
resolved成功回調
成功回調接受的值: 4
輸入11時執行錯誤接口調用reject方法,輸出如下:
數值: 11
rejected失敗回調
失敗執行回調抛出失敗原因: 數字大于10了即将執行失敗回調
失敗執行回調data是什麼: undefined
從上面的結果可知,在then方法中,放在第一位的方法表示正确時處理的方法,放在第二位的方法表示錯誤是調用的方法。
reject: (reason?: any)方法的參數可以是any,這樣在then就是傳什麼輸出什麼。resolve: (value?: any)也一樣,都是回填在then方法中的第一個參數。
promise().then().then().then()
then支援延續任務調用方式,下面所示在第一個promiseClick1(1).then中調用promiseClick2,進入第二個then然後再調用promiseClick3
var that = this
this.promiseClick1(1).then(
function(data) {
console.log('resolved成功回調');
that.promiseClick2(3)
}).then(
function (data) {
that.promiseClick3(3)
})
2、Promise.catch(reject)
處理内容包括:① rejected狀态對應傳回結果,② catch方法前抛出的錯誤
this.promiseClick(11).then(
function(data) {
console.log('resolved成功回調');
console.log('成功回調接受的值:', data);
})
.catch(function(reason, data) {
console.log('catch到rejected失敗回調');
console.log('catch失敗執行回調抛出失敗原因:', reason);
});
錯誤的時候執行結果走catch:
數值: 11
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: 數字大于10了即将執行失敗回調
效果和寫在then的第二個參數裡面一樣。它将大于10的情況下的失敗回調的原因輸出,但是,它還有另外一個作用:在執行resolve的回調(也就是上面then中的第一個參數)時,如果抛出異常了(代碼出錯了),那麼并不會報錯卡死js,而是會進到這個catch方法中。如下:
this.promiseClick(4).then(
function(data) {
console.log('resolved成功回調');
console.log('成功回調接受的值:', data);
console.log(noData);
})
.catch(function(reason, data) {
console.log('catch到rejected失敗回調');
console.log('catch失敗執行回調抛出失敗原因:', reason);
});
在第一個then中調用console.log(noData);方法,由于noData未定義,是以會馬上執行cath方法中,輸出如下
數值: 4
resolved成功回調
成功回調接受的值: 4
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: ReferenceError: noData is not defined
3、Promise.all([p1, p2, ... , p(n)])
p(n)(n = 1, 2, ... )均為Promise執行個體
***注:傳回Promise執行個體的狀态為rejected,即Promise執行個體的狀态為rejected,且沒有catch方法做異常處理
Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
.then(function(results) {
console.log(results);
})
.catch(function (reason, data) {
console.log('catch到rejected失敗回調');
console.log('catch失敗執行回調抛出失敗原因:', reason);
});
},
promiseClick1: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('數值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick1數字大于10了即将執行失敗回調");
}
}, 2000);
})
return p
},
promiseClick2: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('數值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick2數字大于10了即将執行失敗回調");
}
}, 2000);
})
return p
},
promiseClick3: function(num) {
let p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('數值:', num)
if (num <= 10) {
resolve(num);
} else {
reject("promiseClick3數字大于10了即将執行失敗回調");
}
}, 2000);
})
return p
}
① 隻有參數中所有Promise執行個體的狀态都為fulfilled,該方法傳回的Promise執行個體狀态為fulfiiled,意思為所有的都是執行resolve方法,最終才會執行正确的結果,隻要有一個是reject方法,最終都是錯誤的方法,同樣會到then裡的第二個function或者是catch中。
Promise.all([this.promiseClick3(4), this.promiseClick2(5), this.promiseClick1(6)])
.then(function(results) {
console.log(results);
});
輸出:
數值: 4
數值: 5
數值: 6
[4, 5, 6]
② 參數中傳回Promise執行個體的狀态為rejected的數量大于等于1,該方法傳回的Promise執行個體狀态為rejected,傳回資料為第一個狀态變為rejected的參數方法傳回結果
Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
.then(function(results) {
console.log(results);
})
.catch(function (reason, data) {
console.log('catch到rejected失敗回調');
console.log('catch失敗執行回調抛出失敗原因:', reason);
});
輸出:
數值: 4
數值: 12
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: promiseClick2數字大于10了即将執行失敗回調
數值: 11
4、Promise.race([p1, p2, ... , p(n)])
p(n)(n = 1, 2, ... )均為Promise執行個體
all是等所有的異步操作都執行完了再執行then方法,那麼race方法就是相反的,誰先執行完成就先執行回調。
Promise
.race([this.promiseClick3(5), this.promiseClick2(11), this.promiseClick1(12)])
.then(function (results) {
console.log("第一個function:"+results);
}, function (reason) {
console.log("第二個function:" +reason);
});
輸出:
數值: 5
第一個function:5
數值: 11
數值: 12
調用:
Promise
.race([this.promiseClick3(11), this.promiseClick2(5), this.promiseClick1(12)])
.then(function (results) {
console.log("第一個function:"+results);
}, function (reason) {
console.log("第二個function:" +reason);
});
輸出:
數值: 11
第二個function:promiseClick3數字大于10了即将執行失敗回調
數值: 5
數值: 12
從以上例子可以看出,隻會進入一個then的方法,而且是根據第一個執行的狀态進行判斷。
5:Promise.finally( )
finally
方法用于指定不管 Promise 對象最後狀态如何,都會執行的操作
this.promiseClick1(1).then(
function(data) {
console.log('resolved成功回調');
console.log('成功回調接受的值:', nodata);
}).catch(
function(data) {
console.log('catch:' + data);
}).finally(
function(data) {
console.log('不管過程是咋樣的,最終都會走到finally方法中');
})
結果:
數值: 1
resolved成功回調
catch:ReferenceError: nodata is not defined
不管過程是咋樣的,最終都會走到finally方法中
6:promise.done( )
Promise 對象的回調鍊,不管以
then
方法或
catch
方法結尾,要是最後一個方法抛出錯誤,都有可能無法捕捉到(因為 Promise 内部的錯誤不會冒泡到全局)。是以,我們可以提供一個
done
方法,總是處于回調鍊的尾端,保證抛出任何可能出現的錯誤。