js 异步请求怎么写比较优雅?

目前用的 axios 做异步请求,挺好用的,但是请求逻辑复杂的时候总是 return 一个新的 axios,代码一长,写起来有点痛苦。

有没经验丰富的大佬指点一下。

axios.get('abc')
    .then(res => {
        // ...
        return axios.get('def');
    })
    .then(res => {
        // ...
    })
    .catch(err => console.log(err))

上面是现在的写法...

javascript
538 views
Comments
登录后评论
Sign In
·

试试 promise.allpromise.race 写法,可以简化不少,你上面的例子可以这样写:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

等等全部请求完成后再处理

·

async/await 语法就行了:

async function request() {
  const res1 = await axios.get('abc');
  const res2 = await axios.get('def');
  console.log(res1, res2);
}

一楼楼那个写法不能在请求中间打断,有时候下一个请求需要上一个请求的数据时就不能那样写,await 就可以:

async function request() {
  const res1 = await axios.get('abc');
  // 使用首次请求的结果
  const res2 = await axios.post('def', res1.data);
  console.log(res1, res2);
}
·

js 的异步编程可以分为 4 种写法,如下图:

无论后端的异步代码还是前端的异步请求,目前公认最好的写法应该是:“写起来像同步,运行起来像异步”,这样才能发挥两者的优点:

  • 异步:效率高,时间轴紧凑
  • 同步:易开发,易调试

Promise 写法最大的问题就是复杂请求时:then.then.then 无限写下去,中间难以调试,也能难插入自动化测试工具,await 写法优雅不少,写起来像同步,运行起来像异步,配合 all/race 写法可以满足大部分需求。

但是 js 请求中数据竟态问题用 await 写法实现就很麻烦了,考虑这样一个竟态场景:

点击用户 A 的主页,发出请求 request_a,但是请求还没完成的时候切换到用户 B 的主页,发起请求 request_b,但由于网络问题,request_b 比 request_a 先到(顺序反了),结果 request_b 的数据被后到的 request_a 给覆盖了,导致用户 B 的主页显示用户 A 的数据。

这样的 bug 很场景,无论你用的 vuex 还是 redux 做数据管理都可能出现,竟态问题用 await 写法搞定很麻烦,需要写不少代码做检测,为了应对复杂异步编程的需求,js 其实有更好的写法(也是我们目前广泛使用的): yield + generator ,一个经典案例就是 redux-saga,写起来非常优雅,和 await 写法类似,但是能够实现代码分割、解耦,调试非常方便(无需一行代码,使用中间件即可),写起来像这样:

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'

function* fetchData() {
    const res1 = yield call(axios.get, 'abc');
    const res2 = yield call(axios.get, 'def')}

function* rootSaga() {
    yield takeLatest("FETCH_DATA", fetchData);
}

一行代码,加入 takeLatest 就可以解决竟态问题(只接收最后发出请求的结果),这样即使 request_a 数据后到,也会被抛弃,因为 request_a 先发出了请求。

最后一种写法就是 observable 流式写法,典型的就是 redux-observable,控制功能更强大,但是入门门槛也高,写法像异步编程,调试还是没有 generator 写法容易。

·

想当年回调地狱 joy