前言
我們在開發過程中大多會用到promise,想必大家對promise的使用都很熟練了,今天我們就來實現一個簡單的promise,實現的效果如有出入還往指正。
Promise/A+規范:
術語:
整體結構
我們先來梳理一下整體的結果,以便后續好操作
class MyPromise { constructor(fn){  } resolve(){ } then(){ } reject(){ } catch(){ }}Promise理論知識
摘抄至 http://es6.ruanyifeng.com/#docs/promise#Promise-all
Promise對象有以下兩個特點。
(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
總結一下就是promise有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗),還有就是狀態的改變只能是pending -> fulfilled 或者 pending -> rejected,這些很重要
實現構造函數
現在我們開始實現構造函數
class MyPromise { constructor(fn){ if(typeof fn !== 'function') {  throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } ...}構造函數接收一個參數fn,且這個參數必須是一個函數,因為我們一般這樣使用new Promise((resolve,reject)=>{});
然后初始化一下promise的狀態,默認開始為pending,初始化value的值。
fn接收兩個參數,resolve、reject
resolve
class MyPromise { constructor(fn){ if(typeof fn !== 'function') {  throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } ...}當resolve執行,接收到一個值之后;狀態就由 pending -> fulfilled;當前的值為接收的值
reject
class MyPromise { constructor(fn){ if(typeof fn !== 'function') {  throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } reject(reason){ if(this.state !== 'pending') return; this.state = 'rejected'; this.value = reason }}當reject執行,接收到一個值之后;狀態就由 pending -> rejected;當前的值為接收的值
then
class MyPromise { constructor(fn){ if(typeof fn !== 'function') {  throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } reject(reason){ if(this.state !== 'pending') return; this.state = 'rejected'; this.value = reason } then(fulfilled,rejected){ if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) {  return this; } if (typeof fulfilled !== 'function' && this.state === 'fulfilled' ||  typeof rejected !== 'function' && this.state === 'rejected') {  return this; } return new MyPromise((resolve,reject)=>{  if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){  let result = fulfilled(this.value);  if(result && typeof result.then === 'function'){   return result.then(resolve,reject)  }else{   resolve(result)  }  }  if(rejected && typeof rejected === 'function' && this.state === 'rejected'){  let result = rejected(this.value);  if(result && typeof result.then === 'function'){   return result.then(resolve,reject)  }else{   resolve(result)  }  } }) }}then的實現比較關鍵,首先有兩個判斷,第一個判斷傳的兩個參數是否都是函數,如果部不是return this執行下一步操作。
第二個判斷的作用是,比如,現在狀態從pending -> rejected;但是中間代碼中有許多個.then的操作,我們需要跳過這些操作執行.catch的代碼。如下面的代碼,執行結果只會打印1
new Promise((resolve,reject)=>{ reject(1)}).then(()=>{ console.log(2)}).then(()=>{ console.log(3)}).catch((e)=>{ console.log(e)})我們繼續,接下來看到的是返回了一個新的promise,真正then的實現的確都是返回一個promise實例。這里不多說
下面有兩個判斷,作用是判斷是rejected還是fulfilled,首先看fulfilled,如果是fulfilled的話,首先執行fulfilled函數,并把當前的value值傳過去,也就是下面這步操作,res就是傳過去的value值,并執行了(res)=>{console.log(res)}這段代碼;執行完成之后我們得到了result;也就是2這個結果,下面就是判斷當前結果是否是一個promise實例了,也就是下面注釋了的情況,現在我們直接執行resolve(result);
new Promise((resolve,reject)=>{ resolve(1)}).then((res)=>{ console.log(res) return 2 //return new Promise(resolve=>{})})剩下的就不多說了,可以debugger看看執行結果
catch
class MyPromise { ... catch(rejected){  return this.then(null,rejected) }}完整代碼
class MyPromise { constructor(fn){  if(typeof fn !== 'function') {   throw new TypeError(`MyPromise fn ${fn} is not a function`)  }  this.state = 'pending';  this.value = void 0;  fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){  if(this.state !== 'pending') return;  this.state = 'fulfilled';  this.value = value } reject(reason){  if(this.state !== 'pending') return;  this.state = 'rejected';  this.value = reason } then(fulfilled,rejected){  if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) {   return this;  }  if (typeof fulfilled !== 'function' && this.state === 'fulfilled' ||   typeof rejected !== 'function' && this.state === 'rejected') {   return this;  }  return new MyPromise((resolve,reject)=>{   if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){    let result = fulfilled(this.value);    if(result && typeof result.then === 'function'){     return result.then(resolve,reject)    }else{     resolve(result)    }   }   if(rejected && typeof rejected === 'function' && this.state === 'rejected'){    let result = rejected(this.value);    if(result && typeof result.then === 'function'){     return result.then(resolve,reject)    }else{     resolve(result)    }   }  }) } catch(rejected){  return this.then(null,rejected) }}測試
new MyPromise((resolve,reject)=>{ console.log(1); //reject(2) resolve(2) console.log(3) setTimeout(()=>{console.log(4)},0)}).then(res=>{ console.log(res) return new MyPromise((resolve,reject)=>{ resolve(5) }).then(res=>{ return res })}).then(res=>{ console.log(res)}).catch(e=>{ console.log('e',e)})執行結果:
> 1
> 3
> 2
> 5
> 4
原生promise
new Promise((resolve,reject)=>{ console.log(1); //reject(2) resolve(2) console.log(3) setTimeout(()=>{console.log(4)},0)}).then(res=>{ console.log(res) return new Promise((resolve,reject)=>{ resolve(5) }).then(res=>{ return res })}).then(res=>{ console.log(res)}).catch(e=>{ console.log('e',e)})執行結果:
> 1
> 3
> 2
> 5
> 4
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。
新聞熱點
疑難解答