一、什么是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 })
