手寫一個PromiseA+的實現。注意這裏只是模擬,實際上原生的promise在事件隊列中屬於microTask。這裏用setTimeout模擬不是特別恰當。由於setTimeout是一個macroTask。git
/** * 定義Promise * 先實現一個最簡單的。用setTimeout模擬一個異步的請求。 */ function Promise(fn){ var value= null; var callbacks = []; this.then = function(onFulfilled) { callbacks.push(onFulfilled); } function resolve(value){ callbacks.forEach(function(cb){ cb(value); }) } fn(resolve); } // 使用Promise var p = new Promise(function(resolve){ setTimeout(function(){ resolve('這是響應的數據') },2000) }) p.then(function(response){ console.log(response); })
/** * 先看一下前一個例子存在的問題 * 1.在前一個例子中不斷調用then須要支持鏈式調用,每次執行then都要返回調用對象自己。 * 2.在前一個例子中,當鏈式調用的時候,每次then中的值都是同一個值,這是有問題的。其實第一次then中的返回值,應該是第二次調用then中的函數的參數,依次類推。 * 因此,咱們進一步優化一下代碼。 * */ function Promise(fn){ var value= null; var callbacks = []; this.then = function(onFulfilled) { callbacks.push({f:onFulfilled}); return this; } function resolve(value){ callbacks.map(function(cb,index){ if(index === 0){ callbacks[index].value = value; } var rsp = cb.f(cb.value); if(typeof callbacks[index+1] !== 'undefined'){ callbacks[index+1].value = rsp; } }) } fn(resolve); } // 使用Promise var p = new Promise(function(resolve){ setTimeout(function(){ resolve('這是響應的數據') },2000) }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); })
/** * 先看一下前一個例子存在的問題 * 1. 若是在then方法註冊回調以前,resolve函數就執行了,怎麼辦?好比 new Promise的時候傳入的函數是同步函數的話, * then還沒被註冊,resolve就執行了。。這在PromiseA+規範中是不容許的,規範明確要求回調須要經過異步的方式執行。 * 用來保證一致可靠的執行順序。 * * 所以咱們須要加入一些處理。把resolve裏的代碼放到異步隊列中去。這裏咱們利用setTimeout來實現。 * 原理就是經過setTimeout機制,將resolve中執行回調的邏輯放置到JS任務隊列末尾,以保證在resolve執行時, * then方法的回調函數已經註冊完成 * */ function Promise(fn){ var value= null; var callbacks = []; this.then = function(onFulfilled) { callbacks.push({f:onFulfilled}); return this; } function resolve(value){ setTimeout(function(){ callbacks.map(function(cb,index){ if(index === 0){ callbacks[index].value = value; } var rsp = cb.f(cb.value); if(typeof callbacks[index+1] !== 'undefined'){ callbacks[index+1].value = rsp; } }) },0) } fn(resolve); } // 使用Promise,如今即便是同步的立馬resolve,也能正常運行了。 var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); })
/** * 先看一下前一個例子存在的問題 * 1.前一個例子還存在一些問題,若是Promise異步操做已經成功,在這以前註冊的全部回調都會執行, * 可是在這以後再註冊的回調函數就不再執行了。具體的運行下面這段代碼,能夠看到「can i invoke」並無打印出來 * 想要解決這個問題,咱們就須要加入狀態機制了。具體實現看本文件夾下的另外一個js文件裏的代碼。 * */ function Promise(fn){ var value= null; var callbacks = []; this.then = function(onFulfilled) { callbacks.push({f:onFulfilled}); return this; } function resolve(value){ setTimeout(function(){ callbacks.map(function(cb,index){ if(index === 0){ callbacks[index].value = value; } var rsp = cb.f(cb.value); if(typeof callbacks[index+1] !== 'undefined'){ callbacks[index+1].value = rsp; } }) },0) } fn(resolve); } // var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); }) },0)
/** * 在promise01.js中,咱們已經分析了,咱們須要加入狀態機制 * 在這裏實現一下PromiseA+中關於狀態的規範。 * * Promises/A+規範中的2.1Promise States中明確規定了,pending能夠轉化爲fulfilled或rejected而且只能轉化一次, * 也就是說若是pending轉化到fulfilled狀態,那麼就不能再轉化到rejected。 * 而且fulfilled和rejected狀態只能由pending轉化而來,二者之間不能互相轉換 * */ function Promise(fn){ var status = 'pending' var value= null; var callbacks = []; this.then = function(onFulfilled) { // 若是是pending狀態,則加入到註冊隊列中去。 if(status === 'pending'){ callbacks.push({f:onFulfilled}); return this; } // 若是是fulfilled 狀態,此時直接執行傳入的註冊函數便可。 onFulfilled(value); return this; } function resolve(newValue){ value = newValue; status = 'fulfilled'; setTimeout(function(){ callbacks.map(function(cb,index){ if(index === 0){ callbacks[index].value = newValue; } var rsp = cb.f(cb.value); if(typeof callbacks[index+1] !== 'undefined'){ callbacks[index+1].value = rsp; } }) },0) } fn(resolve); } // var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); }) },1000)
/** * 剛纔的例子中,確實打印出了 can i invoke,可是以前then的註冊函數的返回值,並無打印出來。 * 也就是說 1 和 2 並無被打印出來,看下面的註釋 * */ function Promise(fn){ var status = 'pending' var value= null; var callbacks = []; this.then = function(onFulfilled) { if(status === 'pending'){ callbacks.push({f:onFulfilled}); return this; } onFulfilled(value); return this; } function resolve(newValue){ value = newValue; status = 'fulfilled'; setTimeout(function(){ callbacks.map(function(cb,index){ if(index === 0){ callbacks[index].value = newValue; } var rsp = cb.f(cb.value); if(typeof callbacks[index+1] !== 'undefined'){ callbacks[index+1].value = rsp; } }) },0) } fn(resolve); } var p = new Promise(function(resolve){ resolve('aaaaaa') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); // 這裏應該打印的是45行返回的1,可是打印出來的確是aaaaaa return 2; }).then(function(response){ console.log(response); // 這裏應該打印的是48行返回的2,可是打印出來的確是aaaaaa }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); }) },1000) /** * 問題的根源在於什麼呢? * 問題的根源是每次的then的返回值都是p,當狀態是fulfilled,執行的是onFulfilled(value) * 此處的value是p的value,也就是fulfilled狀態的value。根據規範,promise應該是隻能發射單值。 * 而咱們設計了一個callback堆棧中有一系列的值。生生的把promise變成了多值發射。 * * 因此,調整思路,每一個then都應該返回一個promise,這個promise應該是一個全新的promise。 * 具體實現見下一個例子。 */
/** * 根據剛纔的分析,咱們從新優化一下代碼 * 1.去掉以前的多值設計 * 2.每次的then 返回的都是一個全新的promise * */ function Promise(fn){ var status = 'pending' var value= null; var callbacks = []; var self = this; this.then = function(onFulfilled) { return new Promise(function(resolve){ function handle(value){ var res = typeof onFulfilled === 'function' ? onFulfilled(value) : value; resolve(res); } // 若是是pending狀態,則加入到註冊隊列中去。 if(status === 'pending'){ callbacks.push(handle); // 若是是fulfilled 狀態。 }else if(status === 'fulfilled'){ handle(value); } }) } function resolve(newValue){ value = newValue; status = 'fulfilled'; setTimeout(function(){ callbacks.map(function(cb){ cb(value); }) },0) }; fn(resolve); } // var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); }) },1000) /** * 運行一下,完美輸出 * 先是輸出「這是響應的數據」,而後是「1」,而後是「2」, 而後是「can i invoke?」 * * 接下來咱們要好好整理一下代碼了。把一些公用的方法放到構造函數的原型上去。改造以後的例子見下一個例子 */
/** * 根據剛纔的分析,咱們從新優化一下代碼 * 1.把私有屬性掛到實例上去 * 2.把公共方法掛到構造函數的原型上去 * */ function Promise(fn){ this.status = 'pending'; this.value= null; this.callbacks = []; var self = this; function resolve(newValue){ self.value = newValue; self.status = 'fulfilled'; setTimeout(function(){ self.callbacks.map(function(cb){ cb(value); }) },0) } fn(resolve); } Promise.prototype = Object.create(null); Promise.prototype.constructor = Promise; Promise.prototype.then = function(onFulfilled){ var self = this; return new Promise(function(resolve){ function handle(value){ var res = typeof onFulfilled === 'function'? onFulfilled(value) : value; resolve(res); } if(self.status==='pending'){ self.callbacks.push(handle); }else if(self.status ==='fulfilled'){ handle(self.value); } }) } // 使用 var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return 1; }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); }) },1000)
/** * 不出意料,又要拋出問題了。當then註冊的回調函數返回的是promise的時候,從這個then以後的全部then的註冊函數 * 都應該註冊在新返回的promise上。直到遇到下一個回調函數的返回值也是promise。 * * 實現思路: * 在handle中判斷註冊函數返回的是不是promise。若是是的話,則resolve這個返回的promise的值,具體代碼看一下36到38行 * */ function Promise(fn){ this.status = 'pending'; this.value= null; this.callbacks = []; var self = this; function resolve(newValue){ self.value = newValue; self.status = 'fulfilled'; setTimeout(function(){ self.callbacks.map(function(cb){ cb(value); }) },0) } fn(resolve); } Promise.prototype = Object.create(null); Promise.prototype.constructor = Promise; Promise.prototype.then = function(onFulfilled){ var self = this; var promise = new Promise(function(resolve){ function handle(value){ var res = typeof onFulfilled === 'function'? onFulfilled(value) : value; if(res instanceof Promise){ promise = res; resolve(res.value); }else { resolve(res); } } if(self.status==='pending'){ self.callbacks.push(handle); }else if(self.status ==='fulfilled'){ handle(self.value); } }) return promise; } // 使用 var p = new Promise(function(resolve){ resolve('這是響應的數據') }) p.then(function(response){ console.log(response); return new Promise(function(resolve){ resolve('testtest') }) }).then(function(response){ console.log(response); return 2; }).then(function(response){ console.log(response); }) setTimeout(function(){ p.then(function(response){ console.log('can i invoke?'); return new Promise(function(resolve){ resolve('hhhhhh') }) }).then(function(response){ console.log(response); }) },1000)
源碼所有在github上:https://github.com/JesseZhao1...github