vue项目中实时搜索功能的优化——减少请求次数与取消上一次请求

vue项目中实时搜索功能的优化——减少请求次数与取消上一次请求

vue项目中的实时搜索功能是指在用户输入的过程中,不断的向后端发送请求,并展示用户已经输入的内容对应的结果。

在vue项目中实现实时搜索功能的思路一般是:

这里写图片描述

1、监听输入框的输入内容,通过emit将输入内容传递给实时搜索的父组件,同时触发父组件向服务器发送请求;

2、实时搜索的组件在接收到服务器返回的数据后将其传递给子组件进行展示;

下图是实时搜索功能的展示:

在输入框中输入人名,下方实时展示与输入相匹配的结果。

实时搜索功能

上面实现的实时搜索功能存在两个比较明显的问题:

1、每输入一个字符,就向后端发一次请求。如下图所示,当输入完一个人名的时候,就已经向后端发送了好多条请求,太多的请求会给服务器带来压力,其实在实时搜索过程中也并不需要发太多请求;

这里写图片描述

2、由于这些请求都是异步的,虽然发送请求时有先后顺序,但是返回的结果并不会按照发送请求那样有个先后顺序,而是哪个先匹配出结果哪个就先返回,后返回来的结果会将先返回来的结果覆盖,这样导致在最后输入完之后,发现下面展示的并不是最终的搜索结果。如下图所示,当输完“libai”时,下方展示的内容并不是“libai”对应的内容,而是“li”对应的内容。

这里写图片描述

针对上述两个问题进行优化:

1、减少请求次数

将发送请求的命令放入到定时器setTimeout中,然后通过定时器来限制向后端发送请求的次数。例如:规定在输入完一个字符后,如果300ms内没有继续输入,那么300ms后就发送一次请求;如果在300ms内继续输入了内容,那么就会删除上次定时器,重新开始计时,直到300ms内没有继续输入时再发送请求。这样就减少了一些不必要的请求。

具体实现代码:

监听输入框,当输入框中内容变化时触发inputChange事件,remoteSearch是用来触发实时搜索父元素向后端发送请求,通过设置定时器实现对请求次数的限制。

inputChange(val) {
    if(this.timer){
        clearTimeout(this.timer);
    }
    if(val){
        this.timer = setTimeout(() => {
            this.$emit('remoteSearch', val);
        }, 300)
    }else{
        // 输入框中的内容被删为空时触发,此时会清除之前展示的搜索结果
        this.$emit('remoteSearch', val);
    }
},

效果:

减少请求次数效果

这里写图片描述

可以看出,与上面请求了5次相比,通过定时器的限制,请求次数变为了2次。

2、取消上一次请求

从上面已知请求是异步的,发送请求时是按照先后顺序的,返回的结果的顺序则是难以预料的,导致出现最终想要的搜索结果被之前的请求返回结果覆盖。为了解决上述问题,我们需要让返回的结果也有个先后顺序,即先请求的先返回,如果在发送下一次请求时,上一次请求还没结束,那么就取消上一次的发送请求,这样,上面的问题就迎刃而解了。

在vue项目中,异步请求一般使用的是axios对象,取消上一次请求则是利用它的CancelToken属性。

具体实现代码:

// 在文件中引入axios
import axios from 'axios';

......

// 定义一个全局的cancel变量
data() {
    return {
        cancel: null,
    }
}

......

// 监听输入框所触发的实时搜索组件用于向后端请求的方法
remoteSearch(keyword) {
    // 如果存在上一次请求,则取消上一次请求
    if(this.cancel){
        this.cancel();
    }

    // 定义CancelToken,它是axios的一个属性,且是一个构造函数
    let CancelToken = axios.CancelToken;

    // 使用axios的get方法获取请求结果,在请求时需要传入cancelToken参数,
    // 实例化一个CancelToken,实例化后会生成一个类似于id的请求令牌,将它赋值给全局的cancel变量。
    axios.get('/api/sys/user/list', {
        params: { name: keyword },
        cancelToken: new CancelToken((c) => {
            this.cancel = c;
        })
    }).then((res) => {
        // 将请求的结果赋值给personData全局变量,用于展示搜索结果
        if (res.data.code === '0') {
            this.personData = res.data.data || [];
        } else {
            this.personData = [];
        }
    })
},

效果:

取消上一次请求效果

这里写图片描述

可以看出在发下一次请求前,如果上一次请求还没有结束,那么CancelToken会取消上一次请求,这样就避免了因返回结果顺序问题而导致搜索结果被覆盖的问题。

参考文献:

[1] 异步发送的请求—取消操作
[2] 【Vue.js】基于vue的实时搜索,在结果中高亮显示关键词

猜你喜欢

转载自blog.csdn.net/XuM222222/article/details/81979811