function Promise(fn){ //須要一個成功時的回調 var self = this var callback; //一個實例的方法,用來註冊異步事件 self.then = function(done){ callback = done; } // resolve 比 then 先執行 此時 callback 不存在 // 因此 加一個 setTimeout 讓resolve 函數在回調隊列的末尾 // 爲啥是0秒? 爲啥處於回調隊列末尾? //(權威指南)若是以0毫秒的超時時間來調用setTimeout(),那麼指定的函數不會當即執 // 行,相反會把它放到隊列中去,等到前面處於等待狀態的事件處理程序所有執行完成後, // 再「當即」調用它。 // 如下 方式寫 提示 resolve 未定義 涉及閉包 做用域鏈的問題 // setTimeout(function () { // function resolve(value){ // callback && callback(value); // } // }, 0) // 改進方式 function resolve (value) { setTimeout(function () { callback && callback(value) }, 0) } fn(resolve); }
調用promisehtml
// 實例化promise 回調函數fn執行成功,並執行resolve函數,此時在回調隊列裏面添加一 // 一個callback函數,並將resolve的參數傳遞出去。 var promise = new Promise(function (resolve) { resolve(['3', 'aaa']) }) // 調用then函數,並執行then回調,將then函數的參數done回調函數賦值給callback, // 在回調隊列裏面(以前setTimeout添加進去的回調隊列)執行then的回調函數 promise.then(function (data) { console.log('data', data) })
可是以上方式寫,咱們永遠都只能執行then中一個回調隊列,這顯然不健壯。咱們結合js設計模式的發佈--消息訂閱模式,再結合構造函數return this 知識點,稍微改造下:設計模式
function Promise(fn){ //須要一個成功時的回調 var self = this self.deferreds = []; // then函數 回調隊列 儲存容器 //一個實例的方法,用來註冊異步事件 self.then = function(onFulfilled){ self.deferreds.push(onFulfilled) console.log('self.deferreds', self.deferreds) // 調用兩次then 回調隊列會逐個push return self // 鏈式調用then } // 改進方式 function resolve (value) { setTimeout(function () { self.deferreds.forEach(function (deferred) { deferred && deferred(value) }) }, 0) } fn(resolve); }
調用then函數:promise
promise.then(function (data) { console.log('data', data) }).then(function (resp) { console.log('resp', resp) })
衆所周知,構造函數Promise存在三個互斥狀態:pending、fulfilled、rejected。Promise 對象的狀態改變,只有兩種可能:從 pending 變爲 fulfilled 和從 pending 變爲 rejected。只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果。閉包
因此:咱們改進代碼以下:異步
//略 // 初始化設置狀態 self.status = 'pending' //略 // ... //略 // resolve的時候 將狀態置爲 self.status = 'fulfilled' //略
調用執行,一樣能夠獲得咱們想要的數據。
可是
可是
可是
僅僅加上上面兩行代碼是不行的,仔細理解加粗的那幾個字,再結合咱們的代碼來看。
當咱們調用then函數的時候,往咱們then回調隊列裏面push回調函數,最終無論狀態是pending
仍是fulfilled,回調隊列的函數都是被resolve函數觸發的。這樣就違背了這句話:只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果。
當咱們狀態改變爲fulfilled,咱們並無真正改變狀態,每次再從新執行的時候,咱們又從新走了一次then添加回調,而後由resolve來觸發回調的過程。
因此then函數改進代碼以下:函數
// 當status == 'pending'的時候,咱們才往then的回調隊列push回調函數。 // 不然 直接執行回調函數,不會由resolve來觸發then的回調函數執行。 if(self.status == 'pending') { self.deferreds.push(onFulfilled) return self } onFulfilled(value) return self // 鏈式調用then
因此加入value後,最終代碼以下:
基本就實現了鏈式調用then的一個帶有pending 和 fulfilled 狀態的Promise
後續會加上reject(), rejected以及最難理解的串行promise。this
function Promise(fn){ //須要一個成功時的回調 var self = this self.deferreds = []; // then函數 回調隊列 儲存容器 self.status = 'pending' self.value = null //一個實例的方法,用來註冊異步事件 self.then = function(onFulfilled){ if(self.status == 'pending') { self.deferreds.push(onFulfilled) return self } onFulfilled(self.value) return self // 鏈式調用then } // 改進方式 function resolve (newValue) { setTimeout(function () { self.value = newValue self.status = 'fulfilled' self.deferreds.forEach(function (deferred) { deferred && deferred(self.value) }) }, 0) } fn(resolve); }