如何在 Vue 3 中为 axios 调用使用去抖功能

How can I use a debounce function for an axios call in Vue 3

我有使用 axios 从 PHP 脚本获取 JSON 数据的代码。目前此调用是在输入字段时触发的。

除了每次按键都会触发调用外,这很好。我想将此功能去抖动半秒钟。

我尝试从我创建的另一个名为 debounce.js 的文件中导入一个函数,其中包含:

const debounce = (fn, delay) => {
    let timeout
  
    return (...args) => {
      if (timeout) {
        clearTimeout(timeout)
      }
  
      timeout = setTimeout(() => {
        fn(...args)
      }, delay)
    }
  }
  
  export default debounce

我想给这个方法添加去抖:

async fetchResults(){
    await axios.post('includes/searchproducts_json.php', {
        // Post data, add value of input to searchterm
        searchterm: this.$refs.searchterm.value
        
    })
    .then((response)=>{
        // Check if status is 200 (OK) and total_results is not 0
        // If true show results div and fill data
        if (response.status === 200 && response.data.total_results != 0) {
            this.showResultDiv = true
            this.results = response.data.results
            this.totalResults = response.data.total_results
            this.finishedCall = true
        }else{
            this.showResultDiv = false
        }
    })
    .catch((error)=>{
        console.log(error)
    })
    .then((response)=>{
        // Get length of returned object and add to results
        this.finishedCall = true
    })
}

我想将这个去抖动函数包裹在整个方法中,因为我想对整个方法进行去抖动,而不仅仅是检索数据部分。所以我尝试了这个:

setup(){
    async fetchResults = debounce(() => {
        await axios.post('includes/searchproducts_json.php', {
            // Post data, add value of input to searchterm
            searchterm: this.$refs.searchterm.value
            
        })
        .then((response)=>{
            // Check if status is 200 (OK) and total_results is not 0
            // If true show results div and fill data
            if (response.status === 200 && response.data.total_results != 0) {
                this.showResultDiv = true
                this.results = response.data.results
                this.totalResults = response.data.total_results
                this.finishedCall = true
            }else{
                this.showResultDiv = false
            }
        })
        .catch((error)=>{
            console.log(error)
        })
        .then((response)=>{
            // Get length of returned object and add to results
            this.finishedCall = true
        })

    }, 500)
    return { fetchResults }
}

但是我遇到这样的语法错误。我怎样才能为整个 fetchResults 方法正确地实现这个去抖?

这是我没有语法错误的完整 JS 代码:

import debounce from './assets/js/debounce.js'
let app = Vue.createApp({
    data: function(){
        return{
            // Object to fill with JSON response
            results:[],
            showResultDiv: false,
            totalResults: 0,
            finishedCall: false
        }
    },
    computed: {
        // Limit total results in searchdropdown to 6
        resultsToShow() {
            return this.results.slice(0, 6)
        },
        // Set the actual unlimited result amount to totalResults with matching string
        resultString(){
            if(this.totalResults == 1){
                return this.totalResults + ' resultaat'
            }else{
                return this.totalResults + ' resultaten'
            }
        }
    },
    methods:{
        // Function to show div with loading dots until json returned
        loadDiv(condition){
            this.showResultDiv = condition
        },
        async fetchResults(){
            await axios.post('includes/searchproducts_json.php', {
                // Post data, add value of input to searchterm
                searchterm: this.$refs.searchterm.value
                
            })
            .then((response)=>{
                // Check if status is 200 (OK) and total_results is not 0
                // If true show results div and fill data
                if (response.status === 200 && response.data.total_results != 0) {
                    this.showResultDiv = true
                    this.results = response.data.results
                    this.totalResults = response.data.total_results
                    this.finishedCall = true
                }else{
                    this.showResultDiv = false
                }
            })
            .catch((error)=>{
                console.log(error)
            })
            .then((response)=>{
                // Get length of returned object and add to results
                this.finishedCall = true
            })
        }
    }
})

app.mount('#v_search');

你没有说明你遇到了什么语法错误以及发生在什么地方。

虽然我找到了一个,但您似乎想要创建一个函数表达式。

文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function

问题出在你的语法上:

setup(){
    async fetchResults = debounce(() => {
        await axios.post('includes/searchproducts_json.php', {

您不能使用 async 定义函数表达式,此外,您的 await 无效,因为它所在的函数没有 async.

应该是:

setup() {
  const fetchResults = debounce(async () => {
    await axios.post('')

如果你不想使用任何额外的包,你可以像这样在 Vue 3 中使用 debounce。

<input type="search" v-model="query" />
const app = Vue.createApp({
  data() {
    return {
      query: "",
      results: [],
    };
  },
  methods: {
    debounce(func, timeout = 300) {
      let timer;
      return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(this, args);
        }, timeout);
      };
    },
    fetchResults(query) {
      this.debounce(async () => {
        await axios
          .post("includes/searchproducts_json.php", {
            searchterm: query,
          })
          .then((response) => {
            if (response.status === 200 && response.data.total_results != 0) {
              this.showResultDiv = true;
              this.results = response.data.results;
              this.totalResults = response.data.total_results;
              this.finishedCall = true;
            } else {
              this.showResultDiv = false;
            }
          })
          .catch((error) => {
            console.error(error);
          })
          .finally(() => {
            this.finishedCall = true;
          });
      }, 500);
    },
  },
  computed: {
    query: {
      get() {
        return this.query;
      },
      set(val) {
        this.fetchResults(val);
        this.query = val;
      },
    },
  },
});