关于列表项添加删除过程中有过长请求等待中怎么处理?

上面是一个简单的添加删除列表项功能,当我们输入内容确定后,请求时间会很长,当我们再次确定或者删除当前项再添加的时候,可能会由于数据返回的先后顺序,出现顺序错乱。

首先,请求时间过长的处理:

由于请求时间太长,删除或者重新确认的时候,之前的请求还挂着,所以我们应该把之前挂着的请求给终止掉,这里我们用到了AbortController去终止请求,我们可以写一个公共的方法如下:

javascript 复制代码
import qs from "qs";

export const getPendingUrl = (config) =>
  [config.method, config.url, qs.stringify(config.data)].join("&");

export class RequestAbort {
  constructor() {
    this.pendingMap = {};
  }
  addPending(config, key) {
    const mapValues = this.pendingMap[key] || new Map();
    this.pendingMap[key] = mapValues;
    const signalAbortName = getPendingUrl(config);
    if (!mapValues.has(signalAbortName)) {
      const controller = new AbortController(); // 创建一个控制器
      mapValues.set(signalAbortName, controller);
      return controller;
    }
  }
  // 清除请求
  removePending(config, key) {
    const mapValues = this.pendingMap[key];
    const signalAbortName = getPendingUrl(config);
    if (mapValues.has(signalAbortName)) {
      // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
      const controller = mapValues.get(signalAbortName);
      controller.abort();
      mapValues.delete(signalAbortName);
    }
  }
  // 清除对应值的map
  removeFinish(key, value) {
    const mapValues = this.pendingMap[key];
    mapValues && value && mapValues.delete(value)
  }
  // 根据类型key清除
  removeKeyPending(key) {
    const removeValues = this.pendingMap[key];
    if (removeValues) {
      removeValues.forEach((controller) => {
        controller && controller.abort();
      });
      removeValues.clear();
    }
  }
  // 清空
  removeAllPending() {
    this.pendingMap.forEach((item, key) => {
      removeKeyPending(key);
    });
    this.reset();
  }
  // 重置
  reset() {
    this.pendingMap = {};
  }
}

上面我们根据请求的方法、地址、参数作为独立的siganal来处理,getPendingUrl正是做这样子的处理。整个RequestAbort方法是为了处理根据不同请求添加到对应map组,终止对应的请求,或者终止全部请求。比如在我们离开当前页面,但是还有请求处理中,就可以全部清掉。

其次,怎么获取独一无二的请求?

我们在添加删除的时候,我们有可能输入框的参数是一样的,如果按照单存的index来区分,可能会出现顺序错乱,这时候我们就需要唯一值,那么怎么生成唯一值呢?我们可以通过通用的一些方法生成uuid,作为每一个添加的列表项的唯一id,生成uuid的方法如下:

ini 复制代码
// 生成uuid
const hexList = [];
for (let i = 0; i <= 15; i++) {
  hexList[i] = i.toString(16);
}
export const buildUUID = () => {
  let uuid = '';
  for (let i = 1; i <= 36; i++) {
    if (i === 9 || i === 14 || i === 19 || i === 24) {
      uuid += '-';
    } else if (i === 15) {
      uuid += 4;
    } else if (i === 20) {
      uuid += hexList[(Math.random() * 4) | 8];
    } else {
      uuid += hexList[(Math.random() * 16) | 0];
    }
  }
  return uuid.replace(/-/g, '');
}

如果在react中,我们初始state的时候我们就可以根据uuid初始化值,添加的时候通过生成uuid去添加数组值,删除根据uuid去删除如下:

javascript 复制代码
class Test extends Component {
    constructor(props) {
        super(props);
        const initUUID = buildUUID();
        this.state = {
          linkArray: [
            { value: "",uid: initUUID },
          ]
        };
    }
    // 添加
   handleAddLink = () => {
    const newLinkArray = _.cloneDeep(this.state.linkArray);
    const initUUID = buildUUID();
    newLinkArray.push({
      value: "",
      uid: initUUID,
    });
    this.setState({
      linkArray: newLinkArray,
    });
  };
  // 删除
    handleDelete = (uid) => {
    const { linkArray } = this.state
    const newLinkArray = _.cloneDeep(linkArray);
    const index = _.findIndex(newLinkArray, (item) => item.uid === uid);
    newLinkArray.splice(index, 1);
    this.setState({
      linkArray: newLinkArray,
    });
  };
  render() {
      const {linkArray } = this.state;
      return (<div>
          {linkArray.map((item, index) => (
            <div className={styles.linkInputItem} key={item.uid}></div>
            </div>
          ))}
      </div>)
  }
}
最后是我们在请求中的处理:
php 复制代码
import { RequestAbort, getPendingUrl } from "@/utils/abortRequest"

// 创建取消实例
const requestAbort = new RequestAbort()

export const apiRequest = (data) => {
  // 添加取消控制器
  const signalName = getPendingUrl({ method: "post", url: "url", data: data})
  const controller = requestAbort.addPending({ method: "post", url: "url", data: data},'type')
  return request("url", {
    method: "post",
    data,
    signal: controller?.signal,
  });
}
// 取消
export const cancelRequest = async (data) => {
  if(data) {
    return requestAbort.removePending({ method: "post", url: "url", data: data, 'type')
  } else {
    return requestAbort.removeKeyPending('type')
  }
}
相关推荐
NoloveisGod2 分钟前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing3 分钟前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚32 分钟前
实现3D热力图
前端·javascript·3d
理想不理想v42 分钟前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试
EasyNTS1 小时前
无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
前端·javascript·vue.js
老码沉思录1 小时前
React Native 全栈开发实战班 - 数据管理与状态之Zustand应用
javascript·react native·react.js
poloma1 小时前
五千字长文搞清楚 Blob File ArrayBuffer TypedArray 到底是什么
前端·javascript·ecmascript 6
老码沉思录1 小时前
React Native 全栈开发实战班 :数据管理与状态之React Hooks 基础
javascript·react native·react.js
guokanglun1 小时前
Vue.js动态组件使用
前端·javascript·vue.js
我认不到你2 小时前
antd proFromSelect 懒加载+模糊查询
前端·javascript·react.js·typescript