首页 > 解决方案 > Search with axios: cancel previous request when new character

问题描述

I have a searchbar, the results are updated on each letter, but when the user types 3 letters quickly for example, the previous requests are not cancelled so there is a ugly delay before he get his results.

I have read this https://github.com/axios/axios#cancellation and maybe I am a bit tired but I struggle very much adding it in my project. It is almost doing the opposite effect, it now takes forever. Do you have any suggetsion or maybe do you recommend a good tutorial so that I could understand this?

<input v-model="query" type="text" class="form-control" placeholder="Runner name or description"
                   aria-label="Runner name or description"
                   aria-describedby="basic-addon2">


watch: {
            query: {
                handler: _.debounce(function () {
                    this.newSearch()
                }, 100)
            }
        },
methods: {
            searchItems() {
                let filters = {
                    q: this.query
                };

                const CancelToken = axios.CancelToken;
                const source = CancelToken.source();

                axios.post('/Items/find', filters, {
                    cancelToken: source.token
                })
                .catch(function(thrown) {
                    if (axios.isCancel(thrown)) {
                        console.log('Request canceled', thrown.message);
                    }
                })
                .then(
                    response => {
                        if(this.Items!=null){
                            response.data.forEach(element => {
                                this.Items.push(element);
                            });
                        }
                        else
                            this.Items=response.data;
                    }
                );
            },
            newSearch(){
                const CancelToken = axios.CancelToken;
                const source = CancelToken.source();
                source.cancel('Cancel previous request');

                this.countItems();
                this.searchItems();
            },
            showMore(){
                this.startindex = this.startindex+this.nbrows;
                this.searchItems();
            },
            countItems(){
                this.countItems=10;
                let filters = {
                    q: this.query
                };
                axios.post('/Items/count', filters).then(
                    response => {
                        this.countItems=response.data;
                    }
                );
            }
        }

标签: vue.jsaxios

解决方案


我能够让它工作.. 诀窍是在启动 API 调用之前检查取消令牌是否存在等等.. 我不得不将CancelTokenandcancel变量移到Vue对象/组件之外..


此示例在 GitHub 中搜索存储库...

var cancel;
var CancelToken = axios.CancelToken;

new Vue({
  el: "#app",
  data: {
    query: "",
    results: "",
    isLoading: false
  },
  methods: {
    clear() {
      this.isLoading = false;
      this.results = "";
      this.query = "";
    },

    handleSearch: _.debounce(function() {
      this.preApiCall();
    }, 300),

    preApiCall() {
      if (cancel != undefined) {
        cancel();
        console.log("cancelled");
      }
      this.apiCall(this.query);
    },

    apiCall(query) {
      if (query !== "") {
        this.isLoading = true;
        axios({
          method: "get",
          url: "https://api.github.com/search/repositories",
          cancelToken: new CancelToken(function executor(c) {
            cancel = c;
          }),
          params: {
            q: query
          }
        }).then(res => {
          this.results = JSON.parse(JSON.stringify(res.data.items));
          this.isLoading = false;
        }).catch(err => {
          this.results = err.message;
          throw Error(err.message);
          this.isLoading = false;
        });
      } else {
        this.clear();
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

<div id="app">
  <input v-model="query" @keyup.stop="handleSearch" type="text" class="form-control" placeholder="Search">
  <button @click.stop="clear">Clear</button>
  <div v-if="isLoading">Loading...</div>
  <ul v-if="results !== ''">
    <li v-for="(r, index) in results" :key="index">
      {{ r.name }}
    </li>
  </ul>
</div>


[ CodePen 镜像]


取消的请求:

在此处输入图像描述


推荐阅读