### 背景
Promise是異步編程的一種解決方案揽涮,它可以解決異步回調(diào)地獄的問題据某,防止層層嵌套對程序代碼帶來的難維護性录择。既然帶來了方便桦卒,我們就有必要學習它的原理以及底層實現(xiàn)立美,所以筆者就按照PromiseA+規(guī)范寫了一個簡單的Promise,并實現(xiàn)了Promise.all()方灾,Promise.race()等API
### 實現(xiàn)過程
1.定義Promise建蹄,并傳入一個需要執(zhí)行的task函數(shù)碌更,以及Promise中非常重要的三種狀態(tài)
```
//定義Promise的三種狀態(tài)
const PENDING =? 'pending';
const FULFILLED =? 'fulfilled';
const REJECTED =? 'rejected';
function Promise(executor){}
```
2.設置默認狀態(tài),并定義成功和失敗的回調(diào)函數(shù)數(shù)組(為了解決鏈式調(diào)用的問題)
```
?//設置默認狀態(tài)
self.status = PENDING;
//存放成功的回調(diào)函數(shù)的數(shù)組
self.onResolvedCallbacks =[];
//定義存放失敗回調(diào)函數(shù)的數(shù)組
self.onRejectedCallbacks =[];
```
3.定義成功和失敗的回調(diào)函數(shù)實現(xiàn)
```
function resolve(value){?
if(value!=null &&value.then&&typeof value.then == 'function'){
? return value.then(resolve,reject);
}
// This can be implemented with either a“macro-task”mechanism such as setTimeout or setImmediate,or with a“micro-task”mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code
setTimeout(function(){
? if(self.status == PENDING){
? ? self.status = FULFILLED;
? ? self.value = value;
? ? self.onResolvedCallbacks.forEach(cb=>cb(self.value));
? }
})
}
//? When rejected,a promise:
// must not transition to any other state.
// must have a reason,which must not change.
function reject(reason){
setTimeout(function(){
? if(self.status == PENDING){
? ? self.status = REJECTED;
? ? self.value = reason;
? ? self.onRejectedCallbacks.forEach(cb=>cb(self.value));
? }
});
}
```
4.實現(xiàn)then方法洞慎,這個很重要痛单,就是異步任務執(zhí)行成功調(diào)用then方法,依次走下去劲腿,避免了回調(diào)黑洞,其中resolvePromise嚴格按照[PromiseA+規(guī)范](https://promisesaplus.com/)第2.3條去實現(xiàn)
```
Promise.prototype.then = function(onFulfilled,onRejected){
? onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return? value};
? onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
? let self = this;
? let promise2;
? if(self.status == FULFILLED){
? ? return promise2 = new Promise(function(resolve,reject){
? ? ? setTimeout(function(){
? ? ? ? try{
? ? ? ? ? let x =onFulfilled(self.value);
? ? ? ? ? resolvePromise(promise2,x,resolve,reject);
? ? ? ? }catch(e){
? ? ? ? ? reject(e);
? ? ? ? }
? ? ? })
? ? });
? }
? if(self.status == REJECTED){
? ? return promise2 = new Promise(function(resolve,reject){
? ? ? setTimeout(function(){
? ? ? ? try{
? ? ? ? ? let x =onRejected(self.value);
? ? ? ? ? resolvePromise(promise2,x,resolve,reject);
? ? ? ? }catch(e){
? ? ? ? ? reject(e);
? ? ? ? }
? ? ? })
? ? });
? }
? if(self.status == PENDING){
?? return promise2 = new Promise(function(resolve,reject){
?? ? self.onResolvedCallbacks.push(function(){
?? ? ? ? try{
?? ? ? ? ? let x =onFulfilled(self.value);
?? ? ? ? ? //如果獲取到了返回值x,會走解析promise的過程
?? ? ? ? ? resolvePromise(promise2,x,resolve,reject);
?? ? ? ? }catch(e){
?? ? ? ? ? reject(e);
?? ? ? ? }
?? ? });
?? ? self.onRejectedCallbacks.push(function(){
?? ? ? ? try{
?? ? ? ? ? let x =onRejected(self.value);
?? ? ? ? ? resolvePromise(promise2,x,resolve,reject);
?? ? ? ? }catch(e){
?? ? ? ? ? reject(e);
?? ? ? ? }
?? ? });
?? });
? }
}
function resolvePromise(promise2,x,resolve,reject){
? if(promise2 === x){
? ? return reject(new TypeError('構(gòu)成循環(huán)引用'));
? }
? //promise2是否已經(jīng)resolve或reject了
? let called = false;
? if(x instanceof Promise){
? ? if(x.status == PENDING){
? ? ? x.then(function(y){
? ? ? ? resolvePromise(promise2,y,resolve,reject);
? ? ? },reject);
? ? }else{
? ? ? x.then(resolve,reject);
? ? }
? //x是一個thenable對象或函數(shù)揩晴,只要有then方法的對象,
? }else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
?? try{
?? ? let then = x.then;
?? ? if(typeof then == 'function'){
?? ? ? then.call(x,function(y){
? ? ? ? ? if(called)return;
? ? ? ? ? called = true;
? ? ? ? ? resolvePromise(promise2,y,resolve,reject)
?? ? ? },function(err){
?? ? ? ? if(called)return;
?? ? ? ? called = true;
?? ? ? ? reject(err);
?? ? ? });
?? ? }else{
?? ? ? //x不是一個thenable對象
?? ? ? resolve(x);
?? ? }
?? }catch(e){
?? ? if(called)return;
?? ? called = true;
?? ? reject(e);
?? }
? }else{
? ? resolve(x);
? }
}
```
5.Promise.all方法用于將多個 Promise 實例敢课,包裝成一個新的 Promise 實例拯田。只有所有實例的狀態(tài)都變成fulfilled,最后的狀態(tài)才會變成fulfilled垃瞧,此時返回值組成一個數(shù)組蔫劣,傳遞給最終的回調(diào)函數(shù)。
```
function gen(times,cb){
? let result =[],count=0;
? return function(i,data){
? ? result[i]= data;
? ? if(++count==times){
? ? ? cb(result);
? ? }
? }
}
Promise.all = function(promises){
?return new Promise(function(resolve,reject){
?? let done = gen(promises.length,resolve);
?? for(let i=0;i
?? ? promises[i].then(function(data){
?? ? ? done(i,data);
?? ? },reject);
?? }
?});
}
```
6.Promise.race方法同樣是將多個 Promise 實例个从,包裝成一個新的 Promise 實例脉幢。但是只要多個實例之中有一個實例率先改變狀態(tài),最終的狀態(tài)就跟著改變嗦锐。那個率先改變的 Promise 實例的返回值嫌松,就傳遞給最終的回調(diào)函數(shù)。
```
Promise.race = function(promises){
? return new Promise(function(resolve,reject){
? ? for(let i=0;i
? ? ? promises[i].then(resolve,reject);
? ? }
? });
}
```
### 參考鏈接
1.[PromiseA+規(guī)范](https://promisesaplus.com/)
2.[PromiseA+](https://segmentfault.com/a/1190000002452115)