同步更新博客: www.cnblogs.com/GerryOfZhon…
同步更新專欄: zhuanlan.zhihu.com/zhongqiang
同步更新github: github.com/GerryIsWarr…html
半年不迭代,迭代搞半年,說的就是我,這裏有點尷尬了,直接進入主題吧webpack
我記得在這篇博客的時候集成了Promise的,不過那個時候就簡簡單單的寫了一點最基礎,在一些特殊的case上,仍是有點問題的,因此纔有了這個博客。在拜讀了w3c和PromiseA+規範以後,從頭至尾詳細的瞭解了Promise這個東西,而後本身親手寫了一個和es6文檔擁有相同功能的庫。git
promise是一個對象,表示單個異步操做的最終結果。程序員
任何一門技術都不是一個「萬金油」,只有在它最合適的場地出現,纔是實現它最大價值的地方,so,Promise同樣逃不過這個「真香」定律。es6
即便在已經履行或被拒絕以後也能夠訂閱,當某些事情只發生一次,而且做者常常想要在它已經發生以後觀察它的狀態github
圖像,字體等資源的加載loaded屬性,這個屬性僅在資源徹底加載是纔會實現,不然拒絕web
任何一個可能不止一次發生的事件,都不是one-and-done模型的ajax
大的流數據,分步處理流數據,而無需將流的所有內容緩衝到內存中。npm
這裏有個w3c組織搞出來的一個指南--Writing Promise-Using Specifications,建議你們拜讀一下,雖然沒有詳細講解規範,可是對於Promise使用場景和特性作了一次詳細的介紹,包括我上面說的使用場景等等。
promise
Promise自己是一種社區規範--Promises/A+,由Promise A+組織進行制定,它們提供了一個大綱和指導性的方案,只要能實現其所列規範,均可以視做實現了Promise A+,so,後面的各類變種啊,什麼樣的功能,均可以根據本身所需去設計,可是基礎的方案按照A+ 組織規範實現就能夠。
這個大綱比較囉嗦、枯燥、無味,so,咱們靠3張我畫的圖去理解一下Promise
實例化Promise的時候(定義內部狀態的初始值等等),在同步狀態下,首先會執行初始化代碼,好比:new Promise((res,rej)=>{ console.log('這裏就是初始化代碼') }),而後再執行then方法。這個執行順序在promise下是錯誤的,由於在實例代碼中會首先改變Promise狀態,可是前置的callback尚未在then方法中注入,因此要作推遲實例代碼(setTimeout,能夠將任務推到執行週期以後,宏任務),讓then先跑起來,注入狀態變動須要的前置依賴。
在Promise規範中定義了,then方法,必須返回一個Promise,so,Promise2就是then的返回值。而後then的動做就是將全部須要前置依賴的回調函數,Promise狀態,狀態變化的value全都存儲起來。
等待推遲的實例代碼(官方叫:異步)執行以後,觸發了Promise狀態的變化這個動做,而後去改變內部定義的狀態,以及狀態變化所要執行的操做。
內部狀態已經變化完成,可是return的Promise2狀態仍是pending,因此咱們須要將自身的Promise和Promise2的狀態進行同步以及是否可then的持續操做。
以上爲Promise的總體流程思路,它就是這樣跑起來的。不過知道這個流程之後,仍是隻知其一;不知其二的,下面咱們就對核心方法then進行詳細剖析。
then方法須要分3個狀態去解析
a. 首先實例化執行then方法,這個時候初始化的內部狀態都是pending,這個時候,咱們要作一個訂閱和發佈的設計,將then傳入的resolve和reject的回調進行包裝和存儲,並訂閱觸發動做。(這邊的包裝是由於訂閱的時候,不只僅只是執行回調函數,還須要處理promise2的狀態同步問題)
b. 在等待出發的狀態的時候,這個時候狀態沒有變動,因此仍是keep pending狀態,而promise2也是pending;當promise觸發了resolve,這個時候就須要處理以前訂閱的回調了,先改變Promise自身的狀態,而後調用callback,將callback的值傳入解析函數,同步改變Promise2的狀態;觸發reject動做和resolve同樣
c. 這樣,在整個pending鏈路上,自身狀態和promise2狀態全都同步改變完成
a. Promise內部狀態以及變動完畢,內部會存儲PromiseValue的值,直接獲取PromiseValue的值做爲參數,調起then方法傳進來的resolveCallback的函數。
b. 使用同步解析函數,去同步改變Promise2的狀態,以及後續可then的操做
該狀態操做,同resolve操做,只是變動狀態不同
以上爲then方法的全部操做流程,pending的時候最特殊,有個訂閱發佈設計來改變自身狀態,而後同步改變Promise2的狀態。其餘resolve和reject,都是狀態已經變動完畢,直接取狀態變動的值,處理回調,而後同步改變Promise2的狀態值。這邊同步變動Promise2的規則,在A+的規範裏是有定義的。
x表明callback的返回值,首先判斷x和Promise2是否相等,相等拋出TypeError的錯誤(畢竟若是返回值x和Promise2是一個對象的話,那操做就沒啥意義了)
判斷x是不是Promise對象,若是是的話,說明x是可支持then的,而後根據x的狀態進行操做和同步改變Promise2的值,pending就等待執行結束,resolve和reject就分別改變Promise2的狀態
若是x不是Promise對象,判斷x是不是對象或者function,否的話直接resolve Promise2狀態。若是是的話,try-catch捕獲,定義then = x.then是否報錯,若是報錯則reject掉Promise2狀態。
判斷then是不是function,若是是則執行then操做,若是then方法執行了reject,則reject掉Promise2。
若是then執行resolve,則將y替換掉x,從新和Promise2進行狀態的同步改變。
PS:這裏的x.then就是下面的這種情況,A+規範定義這樣的返回值表明仍是可then的,須要處理
temp.then(function (x) {
return {
then: function(resolve, reject) {
resolve(42);
}
}
})
複製代碼
至此整個Promise就結束了,從Promise怎麼去運行,到核心代碼then的處理,以及Promise2的同步改變,這就是所謂的Promise。回過頭來發現,最值得佩服的是這種規範的設計思惟,經過一種設計思惟,將簡單的技術化腐朽爲神奇。因此,我的意見,程序員的進階,最重要的不是代碼的熟練度,而是思惟的進階。熟練度這個是每一個人均可以靠時間堆積出來的,可是更高級的工程師,應該能從總體的視角去了解,而後規劃和設計,將簡單的技術化神奇,將複雜的問題化簡單。
替換以前有問題的createPromise的代碼
將get、post、postForm,obtainBlob,upload進行改造,改方法返回都是Promise(考慮這些都是one-and-done模型,而輪詢和大文件切割上傳2個方法是持續性操做,因此不作改變)
刪除postJSON、promiseAjax方法
// mock功能
mock: {
isOpen: true,
mockData: {}
},
複製代碼
// 全局配置
ajax.config({
baseURL:'http://localhost:3000/',
mock: {
isOpen:true,
mockData: {
'post':'我是mock數據'
}
}
})
// 測試代碼
function request_post() {
ajax.post('post',{data:'ajaxPost'})
.then(x=>{
console.warn(x)
})
}
複製代碼
注意:mockData的key是url的值,不是baseUrl+url的值
完成http其餘協議,put、delete等等
npm的包面向現代化,去除各類polyfill和一些兼容代碼
配置webpack自動打包壓縮
探索通訊和其餘技術的結合玩法
等等...