【问题标题】:Calling `_.debounce` inside a watcher not working在观察者内部调用`_.debounce`不起作用
【发布时间】:2021-08-26 18:02:20
【问题描述】:

考虑以下示例:https://codesandbox.io/s/nuxt-playground-forked-rld4j?file=/pages/index.vue

我尝试制作一个涉及我的一般用例的最小示例。这就是数据格式奇怪的原因。输入 000 或 111,您可以看到它是如何逐步搜索数据的。

基本上它会生成大量数据(我实际上希望拥有更多数据),但您已经注意到性能下降了。现在我想我可以通过对我的观察者进行去抖动来开始提高性能。您可以在上面示例的第 58 行看到这一点。它被注释掉了,因为。您可以将第 57 行注释掉并添加去抖动以查看它不起作用。

这是上面例子的代码:

    <template>
      <div>
        <input type="text" v-model="searchString" />
        SearchString: {{ searchString }}
        <div v-for="(items, index) in this.filteredPosts" :key="items[0]">
          <div v-for="item in items" :key="item">
            {{ item }}
          </div>
          <br />
        </div>
      </div>
    </template>
    
    <script>
    import _ from "lodash";
    
    export default {
      async asyncData() {
        // Just generate some random data
        let animals = ["dog", "cat", "fish", "computer", "c++"];
        // At this point the posts aren't filtered. We just call
        // them filtered because we use this variable name to
        // render and we want the variable filteredPosts available
        // as early as possible.
        let filteredPosts = [];
        const N = 1000;
        const M = 6;
        for (let i = 0; i < N; ++i) {
          let tmpSubArray = [String(i)];
          for (let j = 0; j < M; ++j) {
            tmpSubArray.push(i + " " + j);
          }
          filteredPosts.push(tmpSubArray);
        }
    
        return { filteredPosts };
      },
      data() {
        return {
          searchString: "",
          posts: [],
        };
      },
      watch: {
        searchString() {
          // If this.posts is empty, which is only in the very
          // beginning the case, store a copy of the original
          // posts (which at this point are stored in
          // this.filteredPosts )
          // => from now one this.posts is the original data which
          // won't get changed ever and this.filteredPosts is being
          // changed.
          if (this.posts.length === 0) {
            this.posts = this.filteredPosts;
          }
    
          this.filteredPosts = this.filterByValue();
          /* _.debounce(function () {
            console.log("debounce");
            this.filteredPosts = this.filterByValue();
          });
          */
        },
      },
      methods: {
        filterByValue() {
          // Get searchString
          const searchString = this.searchString.toLowerCase();
    
          // Loop over all posts
          let foo = this.posts.filter((items) => {
            return items.some((item) => {
              if (item.toLowerCase().includes(searchString)) {
                return true;
              }
              return false;
            });
          });
          return foo;
        },
      },
    };
    </script>

现在我不明白为什么它不起作用。有人可以指出我的问题吗?如果有任何其他问题,请指出所有其他问题。 :)

【问题讨论】:

    标签: vue.js nuxt.js


    【解决方案1】:

    首先,增加item数量时组件渲染的延迟,不是过滤功能造成的,而是直接与DOM组件的渲染有关,这不是通过debounce过滤解决的,而是通过减少数量来解决的渲染的项目。例如,在下面的代码框中,我将渲染的项目切片为前 20 个结果,您可以测试即使没有去抖动它也没有延迟,即使初始数据非常大。所以朝那个方向思考(元素的延迟渲染)。

    其次,如果还需要debounce过滤,那么debounce的实现是不正确的。

    lodash中Function的_.debounce()方法用于创建一个 去抖函数,它将给定的函数延迟到指定的函数之后 自上次此时间以来已经过去的等待时间(以毫秒为单位) debounced 函数被调用。

    所以,基本上_.debounce 从现有函数创建一个新的(去抖动的)函数。

    debouncedFunc = _.debounce(existingFunc, timeout)
    

    通过调用观察者

    _.debounce(function () {
            this.filteredPosts = this.filterByValue();
          });
    

    每次触发观察者时,您都会创建一个新的去抖动函数,但永远不要调用它。

    正确的实现包括以下内容:

    // Having some function that need debouncing
    
    existingFunc(){
      // code
    }
    
    // Creating a debounced version from the existing one
    
    const deboncedFunc = _.debounce(existingFunc, 1000)
    
    // Calling the debounced version
    
    debouncedFunc()
    

    https://codesandbox.io/s/gifted-goldwasser-bj2sy?file=/src/components/HelloWorld.vue

    【讨论】:

    • 我明白了。感谢您提供有关延迟加载的附加评论,甚至包括一个示例。 :)
    • 你为什么用mounted()而不是asyncData()?另请注意,由于抛出的错误,您基本上只有N=10'000
    • 我没有使用 asyncData() 因为我没有在示例中包含 Nuxt。关于错误,我没有注意到,谢谢
    【解决方案2】:

    debounce 无法按预期方式工作。

    debounce 返回去抖函数。如果一个函数没有被调用,debounce(...) 是一个空操作。

    需要预先创建去抖动函数,而不是在它应该被去抖动的上下文中,debounce 在这样使用时不可能推迟函数调用,因为它每次调用它都会创建一个新的去抖动函数。

    应该是:

      data() {
        return {
          ...
          debouncedFilterByValue: _.debounce(this.filterByValue)
        }
      },
      watch: {
        searchString() {
          ...
          this.filteredPosts = this.debouncedFilterByValue();
        },
      },
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-24
      • 2020-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多