喵, 忽然想發一話題, 正如標題所言, 想討論一下前端發展到如今, 在 ajax 異步請求的一些設計.javascript
一枚 javaer 在談論 javascript 的東西, 但願不會被打. = =前端
==||| 發了貼很久才發現名詞說錯了。 應該叫作 聲明式 Http 客戶端. 改了下標題.java
在編寫前端網頁時, 會常常用到用異步請求來知足各類需求。那麼咱們是怎麼作的?ios
其實先想一想咱們在獲取數據時, 真正想作的是什麼?git
可能僅僅是 調用api -> 傳參數 -> 獲取返回值, 而後繼續本地的流程.es6
這就是咱們僅僅關心的事.github
可是在十幾年前的恐龍時代, 全部的瀏覽器只提供一個 XMLHttpRequest 對象, 裏面含括了全部關於 Http 請求的設置.ajax
很豐富, 可是也很痛苦, 由於發起一個請求須要設置大量的參數, 寫一大坨無關痛癢的代碼, 只是是爲了發起請求而且獲取結果.spring
後來 JQuery 出現了( 原諒我沒玩過其餘好比 prototype 這種前端框架, 我是個職業後臺 ), $.ajax 簡化了好多參數,axios
可是時代也在進步, 這時候又出來問題, 簡單列幾個痛點:
後來近幾年 es6 遍地開花, 出現了 Promise / fetch 這種專治老司機各類不服的 API, 再有後者 es7 推出的 async/await 直接把回調地獄打進了歷史教科書, 可是後面四個問題依然存在.
而後我看到了 axios 框架, 看了一下 github 裏面的教程, 好好好, 不錯, 該有的都有, 可是對於我這種用慣響應式客戶端的挑剔鬼而言, 是否是能夠再作得更完全一些?
好比 java 的 retrofit, 以及 feign , 都是聲明式客戶端的教科書, 而我依然只想作一件事, 帶着參數調用 api -> 獲取參數, 完事.
最後還能有統一的異常處理派發, 不至於散落一地, 簡而言之, 集中式管理.
最後參考了 retrofit 項目, 寫了一個 retrofitjs 工具, 來看看這又是怎麼玩的( 不要臉的我照搬了 springMVC 的註解 (^○^) ):
首先是定義, 寫出你須要的接口. ( 這是 TypeScript demo, 謝謝 )
@ResponseBody()
@RequestMapping( "/user" )
class UserDetailClient {
@Args(
"createStartTime", "createEndingTime", "updateStartTime", "updateEndingTime",
"status", "nickname", "account", "page", "row"
)
@PostMapping( "/query_by_multi_condition" )
public queryByMultiCondition( createStartTime: number, createEndingTime: number,
updateStartTime: number, updateEndingTime: number,
status: number, nickname: string, account: string,
page: number, row: number ): Promise<any> {
return <any>null;
}
@Args(
"createStartTime", "createEndingTime", "updateStartTime", "updateEndingTime",
"status", "nickname", "account"
)
@PostMapping( "/count_by_multi_condition" )
public countByMultiCondition( createStartTime: number, createEndingTime: number,
updateStartTime: number, updateEndingTime: number,
status: number, nickname: string, account: string ): Promise<any> {
return <any>null;
}
@Args( "id", "status", "name" )
@PostMapping( "/update_user_detail" )
public updateUserDetail( id: string, status: number, name: string ): Promise<any> {
return <any>null;
}
}複製代碼
而後初始化一個客戶端:
let retrofit = new FetchRetrofit.Builder()
.baseUrl( REQUEST_ADDRESS )
.timeout( 0 )
// 忽略 AuthenticationInterceptor, 還有一大坨沒有貼出來
.addInterceptor( new AuthenticationInterceptor() )
.build();
let userDetailClient: UserDetailClient = retrofit.create( UserDetailClient );複製代碼
到如今, retrofit 變量就是一個擁有自動重試, 攔截器鏈, 緩存, 重定向的客戶端對象了.
so, 作完這些事以後, 怎麼搞? 我說, 就這麼搞:
let users = (await userDetailClient.queryByMultiCondition(
createStartTime, createEndingTime, updateStartTime, updateEndingTime,
status, nickname, account, page - 1, range
)).body.result;複製代碼
喲, 就是這樣, 一句話, 不超過100個字符, 但已經等同於一個帶有一切完備功能的異步請求.
我的以爲這纔是 Http 客戶端該有的姿態, 簡潔有力, 直戳痛點.
其實設計也很簡單, 並且這種工具在服務端已經很成熟了, 因此在參考了 retrofit 以後, 我也本身設計了一個可用的雛形, 叫作 retrofitjs.
而在其中, 用到的特性包括 es6 的 Proxy, Decorator, 因此若是真正想用, 只能經過 babel 項目來編譯
其次, 若是用純 JavaScript 實現, 不知道能不能作到兼容 es5, 由於 TypeScript 編譯後, es5 object 是不能繼承 es6 object 的,
因此 TypeScript 實現的支持最多隻能去到 es6.
其實這個項目應該更完善, 好比緩存, 重定向, 自動重發等功能都應該實現, 可是我的時間不容許, 並且我是服務端的人了, 可不能心神不定阿 = =|| 寫出這文章也是爲了告訴你們, 前端的異步請求還能作的更好!