V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ScottHU
V2EX  ›  程序员

是时候该换掉你的 axios 了

  •  
  •   ScottHU · 2023-06-14 12:05:53 +08:00 · 18532 次点击
    这是一个创建于 514 天前的主题,其中的信息可能已经有所发展或是发生改变。

    axios 是一个基于 Promise 的 HTTP 客户端,每周的 npm 下载量 4000W+,如果回到在 10 年前,promise 式的请求工具是一个很大的创新,它解决了请求繁琐的问题,在那个性能要求不那么高的年代可谓是一骑绝尘。但随着时间的推移,Axios 在开发效率和性能方面开始有所落后,现在都已经是 2023 年了,面对日益复杂的需求,我们需要的是一款更具创新性和领先性的请求工具,而 promise 式的请求工具只能被称为传统了,如果你想保持在快速发展的前沿,那么请继续阅读。

    首先我想声明的是,我确实不是标题党,接下来我将通过暴露随着时间的推移,axios 在一些方面表现的力不从心,并推荐一个新的,相比 axios 更具现代化和创新性的请求工具给你,它就是 轻量级的请求策略库 alova

    接下来我们看看 Promise 式请求工具的弱点( axios )

    1. 与 React 、Vue 等框架割裂

    现在,React 、Vue 等前端 UI 框架对于前端来说几乎是不可缺少的,axios 无法和这些框架的状态深度绑定,需要开发者自行维护它们,导致开发效率较低。

    2. 在性能方面毫无作为

    2023 年了,相比 10 年前的应用已经复杂了不知几个数量级,在请求方面要求也越来越高,来保证页面性能的要求,axios 在这方面毫无作为,例如在频繁地重复请求、同时发起多个相同请求等场景。

    3. 臃肿的体积

    根据 bundlephobia 显示,axios 的体积在压缩状态下有 11+kb ,不信的话,你可以点此去查看

    4. 响应数据的 Ts 类型定义混乱

    在使用 axios 时,你可能经常会这样写:

    // 创建一个 axios 实例
    const inst = axios.create({
      baseURL: 'https://example.com/'
    })
    
    // 在响应拦截器中返回 data
    inst.interceptors.response.use(response => {
      if (response.status === 200) {
        return response.data
      }
      throw new Error(response.status)
    })
    
    interface Resp {
      id: number
    }
    inst.get<Resp>('/xxx').then(result => {
      // result 的类型总是为 axios.AxiosResponse<Resp>
      data.data
    })
    

    不知道是 axios 故意为之还是忽略了,以上的发起的 GET 请求中,响应数据result的类型总是axios.AxiosResponse<Resp>的,但其实我们在响应拦截器中已经将response.data返回了,这导致响应数据类型混乱而被困扰。

    在 alova 中是如何解决的呢?

    alova 作为一个更加现代化,更加适应复杂应用的请求方案,也给出了它更加优雅的解决方案。同时为了降低给的学习成本,也保持了和 axios 相似的 api 设计,看起来就很熟悉有木有。

    alova 读作“阿洛娃”,虽然和 axios 一样都是以 a 开头,以下两个名称需要注意区分哦!

    与 UI 框架深度融合,自动管理请求相关数据

    假设我们需要发起一个基本的数据获取请求,以 vue 为例,直接上对比代码。

    axios

    <template>
      <div v-if="loading">Loading...</div>
      <div v-else-if="error" class="error">
        {{ error.message }}
      </div>
      <div v-else>{{ data }}</div>
    </template>
    
    <script setup>
    import axios from 'axios';
    import { ref, onMounted } from 'vue';
    
    const loading = ref(false);
    const error = ref(null);
    const data = ref(null);
    
    const requestData = () => {
      loading.value = true;
      axios.get('http://xxx/index').then(result => {
        data.value = result;
      }).catch(e => {
        error.value = e;
      }).finally(() => {
        loading.value = false;
      });
    }
    onMounted(requestData);
    </script>
    

    alova

    <template>
      <div v-if="loading">Loading...</div>
      <div v-else-if="error" class="error">
        {{ error.message }}
      </div>
      <div v-else>{{ data }}</div>
    </template>
    
    <script setup>
    import { createAlova } from 'alova';
    
    const pageData = createAlova({ baseURL: 'http://xxx' }).Get('/index');
    const { loading, data, error } = useRequest(pageData);
    </script>
    

    在 axios 中需要自己创建对应的请求状态并自行维护,而 alova 却帮你接管了这项工作

    开箱即用的高性能功能

    传统 Promise 式的请求工具主要定位于通过 Promise 的方式简化请求,而提高性能可能是它们最不会考虑的一点,但作为请求策略库的 alova 中却着重突出这一点,在 alova 中默认开启了内存缓存和请求共享,这两项可以极大地提高请求性能,提升用户体验的同时还能降低服务端压力,让我们来一一了解下它们吧。

    内存缓存

    内存模式就是在请求响应后将响应数据保存在本地内存中,当下次再发起相同请求时就会使用缓存数据,而不会再次发送请求,试想一下,当你在实现一个列表页,点击列表项可以进入详情页查看数据,你会想到用户可能会频繁在列表中点击查看详情,当详情数据没有变化时,如果每一次进入详情页都要请求一次未免也太浪费了,而且每次还需要用户等待加载。在 alova 中你可以默认享受到这样的待遇,以下展示下效果

    screenshots.gif

    请求共享

    你可能遇到过这种情况,当一个请求发出但还未响应时,又发起了相同请求,就造成了请求浪费,或者重复提交问题,例如以下三种场景:

    1. 一个组件在创建时会获取初始化数据,当一个页面同时渲染多个此组件时,将会同时发出多次相同请求;
    2. 提交按钮未被禁用,用户点击了多次提交按钮;
    3. 当预加载还未完成时进入了预加载页面,将会发起多次相同请求;

    共享请求就是用来解决这些问题的,它是通过复用请求的方式来实现的,由于这种案例无法直观展示,就不展示了,有兴趣的小伙伴可以自行体验体验。

    除此以外,自称是请求策略库的 alova 还提供了特定场景下的请求策略,我们将在下文中介绍,有兴趣的小伙伴请继续往下看。

    轻量级的体积

    压缩状态下的 alova 只有 4kb+,只有 axios 的 30%+,不信的话,你可以点此去查看

    更加直观的响应数据 TS 类型

    在 axios 中,你想要定义响应数据的类型真是会让人感到困惑,如果你是个 Typescript 的重度用户,alova 可以给你提供完整的类型体验,当你在请求处定义响应数据时的类型后,你可以在多处享受到它,会让你感觉很清晰,我们来看看。

    interface Resp {
      id: number
    }
    const pageData = createAlova({ baseURL: 'http://xxx' }).Get<Resp>('/index');
    const {
      data,  // data 的类型为 Resp
      loading, error, onSuccess, send
    } = useRequest(pageData);
    onSuccess(event => {
      // 在成功回调中获取响应数据时,event.data 的值类型也是 Resp
      console.log(event.data);
    });
    
    const handleClick = async () => {
      // send 函数可以手动再次发送请求,它将可以接收到响应数据,它的值类型还是 Resp
      const data = await send();
    }
    

    至此,相比传统的 Promise 式请求库,你可能已经初步了解了 alova 的厉害。

    但... 它的特性还远不止于此!

    alova 的其他特性

    多 UI 框架同时支持

    alova 同时支持 react 、vue 、svelte ,无论你使用哪种 UI 框架,它都能满足你。

    与 axios 相似的 api 设计,用起来更简单熟悉

    alova 的请求信息构造几乎和 axios 相同,我们来对比一下它们的 GET 和 POST 请求。

    GET 请求

    // axios
    axios.get('/index', {
      // 设置请求头
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
      // params 参数
      params: {
        userId: 1
      }
    });
    
    // alova
    const todoListGetter = alovaInstance.Get('/index', {
      // 设置请求头
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
      // params 参数
      params: {
        userId: 1
      }
    });
    

    POST 请求

    // axios
    axios.post('/login', {
      username: 'xxx',
      password: 'ppp'
    }, {
      // 设置请求头
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
      // params 参数
      params: {
        userId: 1
      }
    });
    
    // alova
    const loginPoster = alovaInstance.Post('/login', {
      username: 'xxx',
      password: 'ppp'
    }, {
      // 设置请求头
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
      // params 参数
      params: {
        userId: 1
      }
    });
    

    (请求策略)高性能分页请求策略

    自动维护分页相关数据和状态,并提供了常用的分页数据操作能力,据官方介绍,可以让列表页流畅性提高 300%,编码难度降低 50%,以下是官方提供的示例,有兴趣的同学可以去看看。

    分页列表示例

    下拉加载示例

    (请求策略)无感数据交互

    这个在我看来,这个无感数据交互请求策略可谓是一大创举,我把它理解为更加可靠的乐观更新,官网是这样解释的:

    无感数据交互是指用户在与应用进行交互时,无需等待即可立即展示相关内容,或者提交信息时也无需等待即可展示操作结果,就像和本地数据交互一样,从而大幅提升应用的流畅性,它让用户感知不到数据传输带来的卡顿。可以更高限度地降低网络波动带来的问题,你的应用在高延迟网络甚至是断网状态下依然可用。

    在我的体验过程中,即使在弱网状态下,也可以让我感受到一种毫无延迟带来的顺畅感,你也来感受下吧。

    screenshots.gif

    据我了解,它使用以下技术:

    1. 持久化的请求队列来保证请求的安全性和串联性;
    2. 请求重试策略机制,来保证请求的顺利完成;
    3. 虚拟响应数据(一个创新的概念),来作为未响应时的数据占位,以便在响应后定位它并替换为实际数据。

    关于无感数据交互更具体的可以在官网了解哦

    数据预拉取

    通过拉取数据的方式预先加载好数据并缓存在本地,当真正用到这部分数据时就可以命中缓存并直接显示数据,这种方式也极大地提升了用户体验。

    写在最后

    总之,alova 作为一个新生代的请求工具,具有很大的潜力,你也想试用的话,可以点击以下链接去了解。

    alova 官网

    alova 的 Github 地址

    写作不易,看都看到这了,不如帮我点个免费的爱心吧!!!感谢你的喜欢

    125 条回复    2023-10-07 17:55:41 +08:00
    1  2  
    Masoud2023
        101
    Masoud2023  
       2023-06-15 09:23:40 +08:00
    alova 这个 API 设计的蛮漂亮的,结合 React 感觉确实不错
    lujiaxing
        102
    lujiaxing  
       2023-06-15 09:27:10 +08:00
    用 axios 很大程度上是为了兼容 IE11, Chrome 49 等相对比较老的浏览器.
    如果不考虑它们的话, 其实直接用 FETCH API 都完全没问题...
    dufu1991
        103
    dufu1991  
       2023-06-15 09:31:45 +08:00
    不管它好不好,反正我是暂时用着 axios ,等 fetch 兼容性起来,直接跳过去。
    jqtmviyu
        104
    jqtmviyu  
       2023-06-15 09:34:04 +08:00
    11K 还大, 我和服务器和用户缺这几 K 吗?
    请求库不绑定框架, 是优点好吧, 我可不想换一个框架熟悉一套 api.
    简单场景我封装下 fetch 就够了
    wwatson
        105
    wwatson  
       2023-06-15 09:38:57 +08:00
    怀疑你是故意来招黑的
    weixiangzhe
        106
    weixiangzhe  
       2023-06-15 09:41:24 +08:00
    东西是不错的,但推广点应该还是要对标到 ahook 的 useRequest ,axios 的简化功能一句带过就好啦
    weixiangzhe
        107
    weixiangzhe  
       2023-06-15 09:45:22 +08:00 via Android
    不过我还是选择那个 use-request 包 加 ky
    xingyuc
        108
    xingyuc  
       2023-06-15 09:45:37 +08:00
    我还以为是这种 https://angular.cn/api/common/http/HttpClient ,使用类似 Observable 的类型,刚想说学不会
    yanbinkwan96
        109
    yanbinkwan96  
       2023-06-15 09:58:31 +08:00
    @fan88 #44 我也是服了,用 jq 的就这素质?
    l4ever
        110
    l4ever  
       2023-06-15 10:05:45 +08:00
    等生态更新吧, 目前用 openapi-typescript-codegen 生成的, 他用你推荐的 alova 我就更新一下咯
    他不用我就懒得更新了.
    shenqi
        111
    shenqi  
       2023-06-15 10:09:00 +08:00
    你说得不错,但是你为什么要在方法名首字母大写?
    gunnarli
        112
    gunnarli  
       2023-06-15 10:54:06 +08:00
    换好麻烦啊。
    Charod
        113
    Charod  
       2023-06-15 11:13:00 +08:00
    已阅,继续 fetch 🐶
    encro
        114
    encro  
       2023-06-15 11:35:33 +08:00   ❤️ 1
    等你实现拦截器,预定义配置,兼容性之类的,发现代码一样肿了。
    obulks
        115
    obulks  
       2023-06-15 12:42:05 +08:00
    11+kb 还臃肿,没地方黑了是吧
    zhoupeng199
        116
    zhoupeng199  
       2023-06-15 13:58:06 +08:00
    发掘金被骂了,发这还被骂
    witcat
        117
    witcat  
       2023-06-15 14:06:54 +08:00
    没必要和 React 结合啊,结合了两边又不一定做得好,请求不一定有 axios 可靠,hook 不一定有 swr 科学。
    当然这只是我猜的,我并没有深入了解,如果两面都能兼顾,那一定会非常受欢迎。
    然鹅,不管是 axios/fetch 与 swr/react query 等等结合,只要有文档和配置,openapi generator 一类的工具都可以一键生成。
    ajan
        118
    ajan  
       2023-06-15 15:04:48 +08:00
    看到标题,忍不住进来恶心一下...
    fan88
        119
    fan88  
       2023-06-15 15:46:24 +08:00
    @yanbinkwan96 是啊,前端工程化一出来耽误老子捞钱啊,本来 JQ 一把梭,网站 F12 扒源码,做个项目嘎嘎方便钱嘎嘎挣。 现在搞的烦的一批。
    Dragonphy
        120
    Dragonphy  
       2023-06-15 20:20:35 +08:00
    不如用 fetch
    lete
        121
    lete  
       2023-06-15 22:24:01 +08:00 via Android
    掘金发,这也发,标题党你是真找喷啊
    nuxio
        122
    nuxio  
       2023-06-16 10:15:28 +08:00
    不好意思 我还是选择 axios ,看你们发帖的内容不爽,耐着性子看你们文档更不爽,一个请求库,你造这么多词干什么?还模型,模你个大头鬼。
    完全没有想要用的欲望,看到都恶心。
    xzjs
        123
    xzjs  
       2023-06-16 10:32:44 +08:00
    等等,说的这几个优点我怎么感觉反而是缺点了,我修改完更新列表,你给我缓存了,我如果要缓存就一个变量的事,不需要 alova 替我做这事啊
    paradox8599
        124
    paradox8599  
       2023-06-16 11:56:25 +08:00 via Android
    这不是 swr ?
    huwenzhe
        125
    huwenzhe  
       2023-10-07 17:55:41 +08:00
    @GzhiYi

    Weekly Downloads: 2385
    Github stars: 1.8k
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2663 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 03:30 · PVG 11:30 · LAX 19:30 · JFK 22:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.