1. 程式人生 > >Promise有哪幾種狀態,各個狀態之間是如何進行轉換的?

Promise有哪幾種狀態,各個狀態之間是如何進行轉換的?

一、什麼是Promise?

1.Promise的結構:

class Promise{
    constructor(exector){
        function resolve(){
            
        }
        function reject(){
            
        }
        exector(resolve,reject)    
    }
    then(){
        
    }
}
​

2.Promise的三種狀態:

pending、fulfilled、rejected(未決定,履行,拒絕),同一時間只能存在一種狀態,且狀態一旦改變就不能再變。promise是一個建構函式,promise物件代表一項有兩種可能結果(成功或失敗)的任務,它還持有多個回撥,出現不同結果時分別發出相應回撥。

1.初始化,狀態:pending
​
2.當呼叫resolve(成功),狀態:pengding=>fulfilled
​
3.當呼叫reject(失敗),狀態:pending=>rejected
const PENDING = "pending";//Promise會一直保持掛起狀態,知道被執行或拒絕。
const FULFULLED = "fulfilled";
const REJECTED = "rejected";
class Promise{
    constructor(exector){
        let self = this;//快取當前promise物件
        self.status = PENDING;//初始狀態,對promise物件呼叫state(狀態)方法,可以檢視其狀態是“pending"、"resolved"、還是”rejected“
        self.value = undefined;// fulfilled狀態時 返回的資訊
        self.reason = undefined;// rejected狀態時 拒絕的原因
        self.onResolveCallBacks = [];// 儲存resolve(成功)狀態對應的onFulfilled函式
        self.onRejectCallBacks = [];// 儲存rejected(失敗)狀態對應的onRejected函式
        let resolve = (value) => {//成功
            if(self.status === PENDING){//如果成功則,狀態由pending=>fulfilled
                self.status = FULFULLED;
                self.value = value;
                self.onResolveCallBacks.forEach(cb=>cb(self.value));//執行釋出
            }
        }
        let reject = (reason) => {//失敗
            if(self.status === PENDING){//如果失敗,則狀態由pending=>rejected
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectCallBacks.forEach(cb=>cb(self.reason));//執行釋出
            }
        }
        
        try{
            exector(resolve,reject)                 
        }catch(e){
            reject(e)
        }
    }
    then(onFulfilled,onRejected){
        let self=this;
        if(self.status === FULFULLED){
            onFulfilled(self.value);//成功值
        }
        if(self.status === REJECTED){
            onFulfilled(self.reason);//拒絕原因
        }
        if(self.status === PENDING){
            self.onResolveCallBacks.push(onFulfilled);//訂閱釋出
            self.onRejectCallBacks.push(onRejected);//訂閱釋出
        }
    }
    //promise的決議結果只有兩種可能:完成和拒絕,附帶一個可選的單個值。如果Promise完成,那麼最終的值稱為完成值;如果拒絕,那麼最終的值稱為原因。Promise只能被決議(完成或拒絕)一次。之後再次試圖完成或拒絕的動作都會被忽略。
}
​
new Promise((resolve,reject)=>{
    resolve("挖坑妹");
    //非同步處理
    //處理結束後、呼叫resolve或reject
}).then((data)=>{
    console.log(data);//"挖坑妹"
},(reason)=>{
    console.log(reason);
})

3.promise的優缺點

​ 優點:

​ 1.Promise 分離了非同步資料獲取和業務邏輯,有利於程式碼複用。

​ 2.可以採用鏈式寫法

​ 3.一旦 Promise 的值確定為fulfilled 或者 rejected 後,不可改變。

​ 缺點:

​ 程式碼冗餘,語義不清。

二、為什麼用Promise?

1.解決回撥地獄

​ 回撥地獄:傳送多個非同步請求時,每個請求之間相互都有關聯,會出現第一個請求成功後再做下一個請求的情況。我們這時候往往會用巢狀的方式來解決這種情況,但是這會形成”回撥地獄“。如果處理的非同步請求越多,那麼回撥巢狀的就越深。出現的問題:

1.程式碼邏輯順序與執行順序不一致,不利於閱讀與維護。

2.非同步操作順序變更時,需要大規模的程式碼重構。

3.回撥函式基本都是匿名函式,bug追蹤困難。

const request = url => {
    return new Promise((resolve,reject) => {
        $.get(url,params => {
            resolve(params)
        });
    });
};
​
request(url).then(params1 => {
    return request(params1.url);   
}).then(params2 => {
    return request(params2.url);
}).then(params3 => {
    console.log(params3);
}).catch(err => throw new Error(err));
​

2.解決非同步

我們都知道js是單執行緒執行程式碼,導致js的很多操作都是非同步執行(ajax)的,以下是解決非同步的幾種方式:

​ 1.回撥函式(定時器)。

​ 2.事件監聽。

​ 3.釋出/訂閱。

​ 4.Promise物件。(將執行程式碼和處理結果分開)

​ 5.Generator。

​ 6.ES7的async/await。

三、怎麼用Promise?

promise有幾種物件方法

1.then方法(非同步執行)

當resolve(成功)/reject(失敗)的回撥函式

//onFulfilled 是用來接收promise成功的值
//onRejected 是用來接收promise失敗的原因
promise.then(onFulfilled,onRejected)

2.resolve(成功)

​ 呼叫onFulfilled

const promise = new Promise((resolve,reject)=>{
    resolve('fulfilled');//狀態:pending=>fulfilled
});
​
promise.then(result =>{//onFulfilled呼叫
    console.log(result);//'fulfilled'   
},result =>{//onRejected不呼叫
    
})
​
​
//注:resolve使用
Promise.resolve('hellow world')相當於
//相當於
const promise = new Promise(resolve=>{
    resolve('hellow world');
})

3.reject(失敗)

​ 呼叫onRejected

const promise = new Promise((resolve,reject)=>{
    reject('rejected');//狀態:pending=>rejected    
});
​
promise.then(result =>{//onFulfilled不呼叫
    
},result =>{//onRejected呼叫
    console.log(result);//'rejected'   
})
​
//注:reject使用
Promise.reject('err')相當於
//相當於
const promise = new Promise((resolve,reject)=>{
    reject('err');
});

4.catch

​ 鏈式寫法中可以捕獲前面then中傳送的異常,這種寫法的好處在於先執行promise操作,然後根據返回的結果(成功或失敗)來呼叫onFulfilled(或者onRrejected)函式。

promise.then(onFulfilled).catch(onRrejected); 

5.all

​ Promise.all接收一個promise物件陣列為引數,處理並行非同步操作會用到,但是需要全部為resolve才能呼叫。這種情況是幾個任務可以並行執行

const promise1= new Promise((resolve,reject)=>{
    resolve('promise1');
});
const promise2= new Promise((resolve,reject)=>{
    resolve('promise2');
});
const promise3= new Promise((resolve,reject)=>{
    resolve('promise3');
});
Promise.all([promise1, promise2, promise3]).then(data => { 
    console.log(data); 
    // ['promise1', 'promise2', 'promise3'] 結果順序和promise例項陣列順序是一致的
}, err => {
    console.log(err);
});

可以從一個promise物件派生出新的promise物件,我們可以要求代表著並行任務的兩個promise物件合併成一個promise物件,由後者負責通知前面的那些任務都已完成。也可以要求代表著任務系列中首要任務的Promise物件派生出一個能代表任務系列中末任務的Promise物件,這樣後者就能知道這一系列的任務是否均已完成。

6.race

​ Promise.race接收一個promise物件陣列為引數,只要有一個promise物件進入Fulfilled或者Rejected狀態的話,就會進行後面的處理。這可以解決多個非同步任務的容錯

function racePromise(time){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(time);
        },time)
    })
}
var startDate = Date.now();
Promise.race([
    racePromise(5),
    racePromise(50),
    racePromise(500),
]).then(function(values){
    console.log(values);5
})