1. 程式人生 > 其它 >new Promise的鏈式操作的用法

new Promise的鏈式操作的用法

複雜的概念先不講,我們先簡單粗暴地把Promise用一下,有個直觀感受。那麼第一個問題來了,Promise是什麼玩意呢?是一個類?物件?陣列?函式?

這麼一看就明白了,Promise是一個建構函式,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。這麼說用Promise new出來的物件肯定就有then、catch方法嘍,沒錯。

鏈式操作的用法

所以,從表面上看,Promise只是能夠簡化層層回撥的寫法,而實質上,Promise的精髓是“狀態”,用維護狀態、傳遞狀態的方式來使得回撥函式能夠及時呼叫,它比傳遞callback函式要簡單、靈活的多。所以使用Promise的正確場景是這樣的:

runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});

在then方法中,你也可以直接return資料而不是Promise物件,在後面的then中就可以接收到資料了,比如我們把上面的程式碼修改成這樣:

runAsync1()
.then(
function(data){ console.log(data); return runAsync2(); }) .then(function(data){ console.log(data); return '直接返回資料'; //這裡直接返回資料 }) .then(function(data){ console.log(data); });

reject的用法

function getNumber(){
    return new Promise(function(resolve, reject){
        //做一些非同步操作
        setTimeout(function
(){ var num = Math.ceil(Math.random()*10); //生成1-10的隨機數 if(num<=5){ resolve(num); } else{ reject('數字太大了'); } }, 2000); }); } getNumber() .then( function(data){ console.log('resolved'); console.log(data); }, function(reason, data){ console.log('rejected'); console.log(reason); } );

catch的用法

效果和寫在then的第二個引數裡面一樣。如果都寫上,只會進入執行then的第二個引數的方法裡。不過它還有另外一個作用:在執行resolve的回撥(也就是上面then中的第一個引數)時,如果丟擲異常了(程式碼出錯了),那麼並不會報錯卡死js,而是會進到這個catch方法中。請看下面的程式碼:

getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
    console.log(somedata); //此處的somedata未定義
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});

也就是說進到catch方法裡面去了,而且把錯誤原因傳到了reason引數中。即便是有錯誤的程式碼也不會報錯了,這與我們的try/catch語句有相同的功能。

all的用法

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});
用Promise.all來執行,all接收一個數組引數,裡面的值最終都算返回Promise物件。這樣,三個非同步操作的並行執行的,等到它們都執行完後才會進到then裡面。那麼,三個非同步操作返回的資料哪裡去了呢?
都在then裡面呢,all會把所有非同步操作的結果放進一個數組中傳給then,就是上面的results。所以上面程式碼的輸出結果就是:

race的用法

all方法的效果實際上是「誰跑的慢,以誰為準執行回撥」,那麼相對的就有另一個方法「誰跑的快,以誰為準執行回撥」,這就是race方法,這個詞本來就是賽跑的意思。race的用法與all一樣,

//請求某個圖片資源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}

//延時函式,用於給請求計時
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('圖片請求超時');
}, 5000);
});
return p;
}

Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});

requestImg函式會非同步請求一張圖片,我把地址寫為”xxxxxx”,所以肯定是無法成功請求到的。timeout函式是一個延時5秒的非同步操作。我們把這兩個返回Promise物件的函式放進race,於是他倆就會賽跑,如果5秒之內圖片請求成功了,那麼遍進入then方法,執行正常的流程。如果5秒鐘圖片還未成功返回,那麼timeout就跑贏了,則進入catch,報出“圖片請求超時”的資訊。執行結果如下:

舉個例子

function isexist(arr){
    return new Promise(resolve,reject=>{
        if(isNaN(arr)){
            resolve('值是NAN')
         }else{
            reject('值是'+arr)
            }
    })

}
isexist(n).then(res=>{console.log(res)}).catch(err=>console.log(err))
值是2
Promise {<fulfilled>: undefined}
isexist(NaN).then(res=>{console.log(res)}).catch(err=>console.log(err))
值是NAN
Promise {<fulfilled>: undefined}

Promise物件可以實現鏈式呼叫,舉個例子

function isexist(arr) {
  return new Promise((resolve, reject) => {
    if (!isNaN(arr)) {
      resolve(arr)
    } else {
      reject(arr)
    }
  })
}
function initNum(arr) {
  return new Promise((resolve, reject) => {
    if (!isNaN(arr)) {
      arr = 123456
      resolve('值是' + arr)
    } else {
      arr = 'promise'
      reject('值是' + arr)
    }
  })
}

//採用鏈式呼叫,最常見的場景就是確認彈出框
isexist(555)
.then(res=>initNum(res))
.then(res => { console.log(res,123) })
.catch(res=>initNum(res))
.catch(err => console.log(err,456))


// 值是123456 123