Promise是什麼
通過列印Promise 發現 Promise是個函式,也是個構造器,在他的原型上有then,catch方法 而自己身上有all,finally,race,reject,resolve方法建立Promise物件
var promise = new Promise(function(resolve, reject) {
console.log('start')
var flag = 1 > 0
if(flag) {
resolve('resolve');
}
else {
reject('reject');
}
});
promise.then(function(result) {
console.log(result);
}, function(err) {
console.log(err);
});
複製程式碼
三種狀態
- Fulfilled 為 已成功 的狀態
- Rejected 為 已失敗 的狀態
- Pending 可以理解為 Promise 物件例項建立時候的 初始 狀態
Promise概念
- Promise是個建構函式,所以建立Promise的方式是new Promise
- 狀態一經改變不會在變
- Promise建構函式接受一個函式作為引數,該函式的兩個引數分別是 resolve 和 reject。它們是兩個函式
- Promise 建立後會立即執行,所以上面程式碼中的start會列印出來
- 因為Promise是處理非同步操作的,所以所有的非同步操作會等到當前所有同步任務執行完畢再去執行非同步任務
resolve & reject
- resolve 函式的作用是,將Promise物件的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在非同步操作成功時呼叫,並將非同步操作的結果,作為引數傳遞出去
- reject 函式的作用是,將Promise物件的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在非同步操作失敗時呼叫,並將非同步操作報出的錯誤,作為引數傳遞出去
- Promise例項生成以後,可以用then方法分別指定resolved狀態和rejected狀態的回撥函式
- resolve & reject 是可以帶引數的,如果攜帶引數,那麼引數將會傳遞給回撥函式,而reject的引數往往是Error物件的例項,表示丟擲去的異常,而resolve不但可以接受普通的資料,而且還可以接受一個新的promise例項
then
p1.then(() => {
return 'helloworld';
}).then((result) => {
console.log(result);
return 520
}).then((result) => {
console.log(result);
});
複製程式碼
- then方法是定義在Promise的原型上
- 作用就是為了給promise狀態發生改變時,呼叫回撥函式
- then()方法可以進行鏈式呼叫,上一個then返回的可以作為下個then的一個函式的引數
- 這就體現了promise 解決非同步操作強大的地方了,在每個then中去處理一個非同步操作,當非同步操作處理結束後返回,才進入下一個then(),這就相當於把一個個非同步操作串了起來,按順序執行
- 在then中返回的資料可以是普通的資料,也可以是promise物件
catch
let p = new Promise((resolve, reject) => {
resolve();
});
p.then(() => {
throw new Error('err');
}).catch((err) => {
console.log(err);
});
複製程式碼
- catch同樣也是Promise原型上的方法
- .catch() 其實也是.then的另一種寫法 .then(null,rejection)
- 當then中發生了異常,可以用.catch() 捕獲異常,如果在promise的整個呼叫中沒有捕獲異常,promise不會將異常丟擲.
- catch可以捕獲整個then呼叫鏈的異常
- 所以通常在寫promise例項的時候需要加入catch()呼叫
finally
- 這個越來越像java的try/catch/finally
- 這個方法是在es2018中加入的
- 作用就是,不管發生了什麼,這個finally的回撥函式肯定會執行
- finally的回撥函式,是不接受引數的,也就是說他的執行與promise的狀態是沒有關係的
Promise Other API
Promise.all
let p1 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('1');
resolve('p1操作');
}, 1000);
})
let p2 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('2');
resolve('p2操作');
}, 1000);
})
let p3 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('3');
resolve('p3操作');
}, 1000);
})
Promise.all([p1, p2, p3])
.then(function(value){
console.log(value);
});
複製程式碼
- Promise.all方法可以將多個promise的例項,組合成一個新的promise物件
- 引數可以不是陣列,但是必須具有Iterator介面,而且返回的每個成員都是Promise例項
- 而新的promise的狀態:當這幾個的狀態都為resolve,時 新promise物件的狀態才是resolve,否則有一個狀態為reject的話,新promise的狀態就是reject
- 這個方法很強大,all的作用其實就是相當於並行的處理多個promise, 當所有的promise都執行完了,才會進入then(),同時也會把這幾個promise返回的資料以陣列的方式傳遞給then
Promise.race
let p1 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('1');
resolve('p1操作');
}, 1000);
})
let p2 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('2');
resolve('p2操作');
}, 1000);
})
let p3 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('3');
resolve('p3操作');
}, 1000);
})
Promise.race([p1, p2, p3])
.then(function(value){
console.log(value);
});
複製程式碼
let p1 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('進行一個介面呼叫,等待返回資料');
resolve('呼叫介面');
}, 10000);
})
let p2 = new Promise((resolve,reject) => {
//模擬做一些非同步操作
setTimeout(function(){
console.log('如果p1 5s 還沒有相應,那麼就執行這個操作');
resolve('介面呼叫失敗,進行操作');
}, 5000);
})
Promise.race([p1, p2])
.then(function(value){
console.log(value);
});
複製程式碼
- Promise.race跟all 類似, 也是將多個promise的例項組合成一個promise物件
- 區別在於新promise的狀態為這些promise中第一個狀態被修改的promise的狀態,rece也就是說誰跑的快就是誰,那個率先改變的 Promise 例項的返回值,就傳遞給p的回撥函式
- 這回返回的資料就不是陣列了,而是第一個返回的resolve中傳遞的資料
Promise.resolve
如果想把一個物件轉換成為一個Promise物件可以使用 Promise.resolve() 他的引數可以有三種可能
- 是一個Promise例項,如果是一個promise例項,那麼Promise.resolve 將不做任何修改,直接返回這個例項
- 如果引數是個thenable物件,也就是說物件中有then方法,Promise.resolve 把這個物件轉換成promise物件時,會立即呼叫裡面的then方法
- 引數根本就不是物件的時候,Promise.resolve 會把它變成一個Promise物件,並且狀態為resolved
- 當建立的promise例項不存在非同步操作,則返回的promise例項一出生狀態就是resolved,所以立即會呼叫回撥函式
Promise.reject
也是返回一個promise例項,不用的是返回的例項的狀態為reject