前端通訊:ajax設計方案(十)--- 完善Promise A+規範,增長mock數據功能

半年不迭代,迭代搞半年,說的就是我,這裏有點尷尬了,直接進入主題吧html

我記得在這篇博客的時候集成了Promise的,不過那個時候就簡簡單單的寫了一點最基礎,在一些特殊的case上,仍是有點問題的,因此纔有了這個博客。在拜讀了w3c和PromiseA+規範以後,從頭至尾詳細的瞭解了Promise這個東西,而後本身親手寫了一個和es6文檔擁有相同功能的庫。webpack

 

什麼是promise?git

promise是一個對象,表示單個異步操做的最終結果。程序員

 

何時使用?es6

任何一門技術都不是一個「萬金油」,只有在它最合適的場地出現,纔是實現它最大價值的地方,so,Promise同樣逃不過這個「真香」定律。github

1. one-and-done操做模型web

    • 異步I / O操做:從存儲API讀取或寫入的方法能夠返回承諾。
    • 異步網絡操做:經過網絡發送或接收數據的方法能夠返回承諾。
    • 長時間運行的計算:須要一段時間來計算某些東西的方法能夠在另外一個線程上完成工做,返回結果的承諾。
    • 用戶界面提示:要求用戶回答的方法能夠返回承諾。

2. One-Time "Events」模型ajax

  即便在已經履行或被拒絕以後也能夠訂閱,當某些事情只發生一次,而且做者常常想要在它已經發生以後觀察它的狀態npm

3.更多狀態的變化promise

  圖像,字體等資源的加載loaded屬性,這個屬性僅在資源徹底加載是纔會實現,不然拒絕

 

不建議使用promise的場景

1. 任何一個可能不止一次發生的事件,都不是one-and-done模型的

2. 大的流數據,分步處理流數據,而無需將流的所有內容緩衝到內存中。

 

這裏有個w3c組織搞出來的一個指南--Writing Promise-Using Specifications,建議你們拜讀一下,雖然沒有詳細講解規範,可是對於Promise使用場景和特性作了一次詳細的介紹,包括我上面說的使用場景等等。

 

以上講的更多偏向應用層的知識點,下面就讓咱們深刻它的根本去了解Promise是如何實現的。

Promise自己是一種社區規範--Promises/A+,由Promise A+組織進行制定,它們提供了一個大綱和指導性的方案,只要能實現其所列規範,均可以視做實現了Promise A+,so,後面的各類變種啊,什麼樣的功能,均可以根據本身所需去設計,可是基礎的方案按照A+ 組織規範實現就能夠。

這個大綱比較囉嗦、枯燥、無味,so,咱們靠3張我畫的圖去理解一下Promise

 

第一張:promise總體流程圖

1.  實例化Promise的時候(定義內部狀態的初始值等等),在同步狀態下,首先會執行初始化代碼,好比:new Promise((res,rej)=>{ console.log('這裏就是初始化代碼') }),而後再執行then方法。這個執行順序在promise下是錯誤的,由於在實例代碼中會首先改變Promise狀態,可是前置的callback尚未在then方法中注入,因此要作推遲實例代碼(setTimeout,能夠將任務推到執行週期以後,宏任務),讓then先跑起來,注入狀態變動須要的前置依賴。

2.  在Promise規範中定義了,then方法,必須返回一個Promise,so,Promise2就是then的返回值。而後then的動做就是將全部須要前置依賴的回調函數,Promise狀態,狀態變化的value全都存儲起來。

3.  等待推遲的實例代碼(官方叫:異步)執行以後,觸發了Promise狀態的變化這個動做,而後去改變內部定義的狀態,以及狀態變化所要執行的操做。

4.  內部狀態已經變化完成,可是return的Promise2狀態仍是pending,因此咱們須要將自身的Promise和Promise2的狀態進行同步以及是否可then的持續操做。

 

以上爲Promise的總體流程思路,它就是這樣跑起來的。不過知道這個流程之後,仍是隻知其一;不知其二的,下面咱們就對核心方法then進行詳細剖析。

 

第二張:then方法核心解析

then方法須要分3個狀態去解析

1. pending 狀態

  a. 首先實例化執行then方法,這個時候初始化的內部狀態都是pending,這個時候,咱們要作一個訂閱和發佈的設計,將then傳入的resolve和reject的回調進行包裝和存儲,並訂閱觸發動做。(這邊的包裝是由於訂閱的時候,不只僅只是執行回調函數,還須要處理promise2的狀態同步問題)

  b. 在等待出發的狀態的時候,這個時候狀態沒有變動,因此仍是keep pending狀態,而promise2也是pending;當promise觸發了resolve,這個時候就須要處理以前訂閱的回調了,先改變Promise自身的狀態,而後調用callback,將callback的值傳入解析函數,同步改變Promise2的狀態;觸發reject動做和resolve同樣

  c. 這樣,在整個pending鏈路上,自身狀態和promise2狀態全都同步改變完成

2. resolve 狀態

  a. Promise內部狀態以及變動完畢,內部會存儲PromiseValue的值,直接獲取PromiseValue的值做爲參數,調起then方法傳進來的resolveCallback的函數。

  b. 使用同步解析函數,去同步改變Promise2的狀態,以及後續可then的操做

3. reject 狀態 

  該狀態操做,同resolve操做,只是變動狀態不同

 

以上爲then方法的全部操做流程,pending的時候最特殊,有個訂閱發佈設計來改變自身狀態,而後同步改變Promise2的狀態。其餘resolve和reject,都是狀態已經變動完畢,直接取狀態變動的值,處理回調,而後同步改變Promise2的狀態值。這邊同步變動Promise2的規則,在A+的規範裏是有定義的。

 

第三張:同步改變Promise2狀態以及是否可繼續then的操做

狀態同步改變和是否可持續then的操做解析流程,都按照A+規範去判斷

1. x表明callback的返回值,首先判斷x和Promise2是否相等,相等拋出TypeError的錯誤(畢竟若是返回值x和Promise2是一個對象的話,那操做就沒啥意義了)

2. 判斷x是不是Promise對象,若是是的話,說明x是可支持then的,而後根據x的狀態進行操做和同步改變Promise2的值,pending就等待執行結束,resolve和reject就分別改變Promise2的狀態

3. 若是x不是Promise對象,判斷x是不是對象或者function,否的話直接resolve Promise2狀態。若是是的話,try-catch捕獲,定義then = x.then是否報錯,若是報錯則reject掉Promise2狀態。

4. 判斷then是不是function,若是是則執行then操做,若是then方法執行了reject,則reject掉Promise2。

5. 若是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。回過頭來發現,最值得佩服的是這種規範的設計思惟,經過一種設計思惟,將簡單的技術化腐朽爲神奇。因此,我的意見,程序員的進階,最重要的不是代碼的熟練度,而是思惟的進階。熟練度這個是每一個人均可以靠時間堆積出來的,可是更高級的工程師,應該能從總體的視角去了解,而後規劃和設計,將簡單的技術化神奇,將複雜的問題化簡單。

 

整個代碼我就不貼出來了,太長了,能夠到 github 上查看,功能完善了,支持all、race、resolve、reject方法

 

 

在ajax-js的庫的變更,以下:

1. 替換以前有問題的createPromise的代碼

2. 將get、post、postForm,obtainBlob,upload進行改造,改方法返回都是Promise(考慮這些都是one-and-done模型,而輪詢和大文件切割上傳2個方法是持續性操做,因此不作改變)

3. 刪除postJSON、promiseAjax方法

 

ajax-js庫增長新功能:mock功能

全局配置參數:

    // mock功能
 mock: { isOpen: true, mockData: {} },

 

流程以下:

 

demo:

// 全局配置
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的值

 

 結束語:

ajax-js.1.9.2完成了,一直在思考還有什麼須要改進的東西,以後的迭代須要走的方向

1. 完成http其餘協議,put、delete等等

2. npm的包面向現代化,去除各類polyfill和一些兼容代碼

3. 配置webpack自動打包壓縮

4. 探索通訊和其餘技術的結合玩法

5. 等等...

 

github地址:https://github.com/GerryIsWarrior/ajax   對你有幫助或啓發,點個小星星,支持繼續研究下去

相關文章
相關標籤/搜索