喵, 忽然想发一话题, 正如标题所言, 想讨论一下前端发展到如今, 在 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.
其实这个项目应该更完善, 好比缓存, 重定向, 自动重发等功能都应该实现, 可是我的时间不容许, 并且我是服务端的人了, 可不能心神不定阿 = =|| 写出这文章也是为了告诉你们, 前端的异步请求还能作的更好!