el-radio-button切换不同的按钮获取到列表的数据不同,多次快速切换偶尔发现显示的数据混乱

场景:

用户快速切换Tab,由于网络延迟等原因,造成数据混乱,很可能最后停留的Tab所展示的内容,并不是用户想要看到的内容.

原理:

多个异步操作同时竞争资源或者执行时造成的竞态

解决办法:
1,通过取消请求实现(切换的时候发现上个还在请求,就直接取消请求)

1.1, Fetch API abortController

const axios = require('axios');
 
const controller = new AbortController();
const signal = controller.signal;
 
axios.get('https://your-api.com/data', {
  signal,
}).then(response => {
  console.log(response.data);
}).catch(error => {
  console.log('AbortController error:', error.message);
  if (axios.isCancel(error)) {
    console.log('Request canceled:', error.message);
  } else {
    // handle non-cancel errors
  }
});
 
controller.abort();

1.2, Axios cancelToken(但是cancelToken 从 v0.22.0 开始已被 axios 弃用。原因是基于实现该 API 的提案 cancelable promises proposal 已被撤销。)

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
 
axios.get('/someApi', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});
 
// 取消请求(可以在任何时候调用)
source.cancel('Operation canceled by the user.');

1.3, XMLHttpRequest 取消请求

xhr.abort()
2,通过忽略请求实现(忽略了请求之后的赋值操作)

2.1, 可以基于指令式 promise 封装一个自动忽略过期请求的高阶函数 onlyResolvesLast。在每次发送新请求前,cancel 掉上一次的请求,忽略它的回调。

function onlyResolvesLast(fn) {
  // 保存上一个请求的 cancel 方法
  let cancelPrevious = null; 
  const wrappedFn = (...args) => {
    // 当前请求执行前,先 cancel 上一个请求
    cancelPrevious && cancelPrevious();
    // 执行当前请求
    const result = fn.apply(this, args); 
    // 创建指令式的 promise,暴露 cancel 方法并保存
    const { promise, cancel } = createImperativePromise(result);
    cancelPrevious = cancel;
    return promise;
  };
  return wrappedFn;
}

2.2, 使用队列
与使用锁类似,我们把每个请求都放进队列里,对每次返回的请求进行判断,如果这个请求不是最新的请求,那么就忽略掉

3,通过禁用页面(如果数据没有请求完成就禁止点另外的tab)

可以配合使用loading

Logo

前往低代码交流专区

更多推荐