這個文章,展示的是一個實現Promise的思路,以及如何發現和處理問題的情境。git
若是咱們想要本身實現一個簡單的Promise
,那現有規範規定的Promise
確定是咱們最好的參照。es6
咱們先看下Promise
怎麼使用:github
var promise1 = new Promise(function(resolve, reject){ // 成功後的TODO resolve(value); // 失敗後的TODO reject(err); })
來看下返回的promise1
是什麼,以及它的結構是怎麼樣的:數組
再進行一些具體操做promise
var promise1 = new Promise(function(resolve, reject) { resolve('zqz') }) promise1.then(function(result) { console.log(result) }).catch(function(err){ console.log(err) }) // => 'zqz'
var promise1 = new Promise(function(resolve, reject) { reject('出現異常') }) promise1.then(function(result) { console.log(result) }).catch(function(err){ console.log(err) }) // => '出現異常'
從Promise的 使用方式上 和 實例 能夠看到哪些東西:框架
reject
和 resolve
reject
和 resolve
都有一個參數, 參數類型不限定then
和 catch
,同時then能夠有多個,因此須要一個回掉函數隊列PromiseStatus
和 PromiseValue
pending
, fulfilled
,rejected
根據上面的分析狀況,咱們先簡單的來構造一個雛形。異步
function Promise(fn) { this.PromiseStatus = 'pending'; this.PromiseValue = ''; this.resolvedCb = []; this.rejectedCb = []; var self = this; var resolve = function (result) { // 判斷狀態 if (self.PromiseStatus === 'pending') { self.PromiseStatus = 'resolved'; self.PromiseValue = result; // resolvedCb 隊列依次執行 for (var i = 0;i < self.resolvedCb.length; i++) { self.resolvedCb[i](result) } } } var reject = function (err) { // 判斷狀態 if (self.PromiseStatus === 'pending') { self.PromiseStatus = 'rejected'; self.PromiseValue = err; // rejectedCb 隊列依次執行 for (var i = 0;i < self.rejectedCb.length; i++) { self.rejectedCb[i](result) } } } // 錯誤處理 -> rejected try { fn(resolve, reject) } catch(e) { reject(e) } }
固然這還不夠,由於重要的兩個功能then
和catch
尚未實現。async
分析下then
的使用函數
promise1.then(function(value){ // todo return value; }) .then(function(value1){ // todo return value1; }) .then(function(value2){ // todo return value2; })
return
的值 直接做爲下個 then
中匿名函數的入參根據Promise返回的實例,咱們可看出來then
是掛載在 Promise 的原型鏈上。測試
咱們先實現一個大致的框架:
Promise.prototype.then = function (handleSuccess, handleFail) { var self = this; var PromiseStatus = this.PromiseStatus; if(typeof handleSuccess === 'function') { handleSuccess = handleSuccess; } else { handleSuccess = function (result) {} } if(typeof handleFail === 'function') { handleFail = handleFail; } else { handleFail = function (err) {} } if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(handleSuccess); self.rejectedCb.push(handleFail); }) } if(PromiseStatus === 'resolved') { return new Promise(function(resolve, reject) { var result = handleSuccess(self.PromiseValue); resolve(result); }) } if(PromiseStatus === 'rejected') { return new Promise(function(resolve, reject) { var result = handleFail(self.PromiseValue); reject(result); }) } }
咱們先用一下,看下是否符合指望
方式一(無異步操做):
function promise1() { return new Promise(function(resolve, reject){ console.log('執行promise1') resolve('zqz'); }) } promise1().then(function(result){ console.log('執行1', 'result:'+result) return result + '11'; }) .then(function(result){ console.log('執行2', 'result:'+result) return result + '22'; }) // => 執行promise1 // => 執行1 result:zqz // => 執行2 result:zqz11 // => Promise {PromiseStatus: "resolved", PromiseValue: "zqz1122", resolvedCb: Array(0), rejectedCb: Array(0)}
這樣使用沒有問題!
方式二(有異步操做):
function promise1() { return new Promise(function(resolve, reject){ // 異步操做 setTimeout(function(){ console.log('執行promise1') resolve('zqz'); },1000) }) } promise1().then(function(result){ console.log('執行1', 'result:'+result) return result + '11'; }) .then(function(result){ console.log('執行2', 'result:'+result) return result + '22'; }) // => 執行promise1 // => 執行1 result:zqz
一旦出現異步操做,就有問題!很明顯,Promise的主要做用就是控制異步操做的執行順序。
確定是哪裏有問題,咱們來分析一下,異步的時候 有哪些 不一樣
PromiseStatus
是pending
狀態在來看下咱們在pending
時候的處理
... // 異步時 if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { // 這裏只是將函數塞入隊列,而後就沒有而後來。。。這是有問題的 self.resolvedCb.push(handleSuccess); self.rejectedCb.push(handleFail); }) } ...
這時候咱們的兩個數組:resolvedCb
和rejectedCb
就發揮做用了,因爲咱們不知道異步何時結束,可是咱們能夠根據他們定義的前後順序注入到 隊列
中,而後根據 順序
依次執行,這樣也就保證了異步操做的執行順序。
if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { // 一個個的塞入隊列 self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); resolve(res); }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); reject(er); }) }) }
這時候咱們用多個異步操做
來測試一下
function async1() { return new Promise(function(resolve, reject){ // 異步操做 setTimeout(function(){ console.log('執行async1') resolve('zqz1'); },3000) }) } function async2() { return new Promise(function(resolve, reject){ // 異步操做 setTimeout(function(){ console.log('執行async2') resolve('zqz2'); },1000) }) } function async3() { return new Promise(function(resolve, reject){ // 異步操做 setTimeout(function(){ console.log('執行async3') resolve('zqz3'); },2000) }) } // return 一個新的promise async1().then(function(result){ console.log('result = ' + result) return async2(); }).then(function(result){ console.log('result = ' + result) return async3(); }).then(function(result){ console.log('result = ' + result) return result; }) // => Promise {PromiseStatus: "pending", PromiseValue: "", resolvedCb: Array(0), rejectedCb: Array(0)} // => 執行async1 // => result = zqz1 // => result = [object Object] // => result = [object Object] // => 執行async2 // => 執行async3
這裏有兩個問題:
咱們再來分析下,着重看下下面這塊代碼
... if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { // 這裏返回的res有多是promise,可是咱們沒有作處理 var res = handleSuccess(self.PromiseValue); resolve(res); }) self.rejectedCb.push(function(err) { // 這裏返回的res有多是promise,可是咱們沒有作處理 var er = handleFail(self.PromiseValue); reject(er); }) }) } ...
由於咱們返回的是Promise,因爲咱們沒有作處理,致使沒法正確的獲取到值。
... if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); if (res instanceof Promise) { res.then(resolve, reject); } else { resolve(res); } }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); if (er instanceof Promise) { er.then(resolve, reject); } else { reject(er); } }) }) } ...
若是返回的是一個Promise,就繼續塞入到then裏面。
在執行一下:
async1().then(function(result){ console.log('result = ' + result) return async2(); }).then(function(result){ console.log('result = ' + result) return async3(); }).then(function(result){ console.log('result = ' + result) return result; }) // => Promise {PromiseStatus: "pending", PromiseValue: "", resolvedCb: Array(0), rejectedCb: Array(0)} // => 執行async1 // => result = zqz1 // => 執行async2 // => result = zqz2 // => 執行async3 // => result = zqz3
最後一個簡單完整的 then:
Promise.prototype.then = function (handleSuccess, handleFail) { var self = this; var PromiseStatus = this.PromiseStatus; if(typeof handleSuccess === 'function') { handleSuccess = handleSuccess; } else { handleSuccess = function (result) {} } if(typeof handleFail === 'function') { handleFail = handleFail; } else { handleFail = function (err) {} } if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); if (res instanceof Promise) { res.then(resolve, reject); } else { resolve(er); } }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); if (er instanceof Promise) { er.then(resolve, reject); } else { reject(er); } }) }) } if(PromiseStatus === 'resolved') { return new Promise(function(resolve, reject) { var result = handleSuccess(self.PromiseValue); resolve(result); }) } if(PromiseStatus === 'rejected') { return new Promise(function(resolve, reject) { var result = handleFail(self.PromiseValue); reject(result); }) } }