Javascript无限滚动节流/去抖动

Javascript infinite scroll throttling/debouncing

本文关键字:抖动 无限 滚动 Javascript      更新时间:2023-09-26

我在几个页面上设置了这个无限滚动功能。它运行得很好,但加载更多项目的Ajax调用会进行多次数据库调用,每次都要加载大量图像,通常需要几秒钟的时间才能加载。根据我的连接情况,我将其计时在3到7秒之间。正因为如此,当浏览器决定多次启动滚动事件时,它可能会变成真正的火车残骸。我怎么能对它进行节流或取消阻塞,这样浏览器就不会在几秒钟内多次运行Ajax调用,并使一切都停止?

$(document).ready() 
{
    //Infinite scroll
   $(window).on('scroll', _.debounce( function(){
      var height = $(window).height();
      var scrollTop = $(window).scrollTop();
      var dHeight = getDocHeight();
      if( height + scrollTop >= dHeight - 100) 
      {
        //Display items that were previously hidden 
         showAllItems();
         if(!vloaded < START_NUM && !done){
             //Load next set of items
             $.ajax
             ({
              type: "POST",
              url: "/organizer/getMore",
              data: { filter: vfilter, loaded: vloaded },
              dataType: "html",
              success: function( responseText, textStatus, XHR )
              {
                if(responseText.indexOf("// GRID ENTRY //") < 0){   //Out of items to load
                    done = true;
                }
                else{
                    //Display items that were previously hidden 
                    showAllItems();
                    // select the element with the ID grid and insert the HTML
                    $( "#grid" ).append( responseText );
                    //alert("Loaded "+vloaded+" items");
                }
              }
            });
          // global variable
          vloaded +=LOAD_NUM;
      } // if
      }
    }
  }, 500, true)); // on
} // ready

编辑:

我下载了下划线并添加了debounce函数,但现在Ajax调用似乎根本没有运行。即使我没有将immediate设置为true,它也应该在我停止滚动后很快执行,但它根本不执行。

Undercore库有这样的方法:

  • _.throttle()
  • _.debounce()

你可能想要_.debounce。如果您不想将Undercore添加为额外的依赖项,您可以从源代码中为所需的方法创建一个独立的方法。

看看下划线。他们有一个很棒的小防反弹包装器,可以接受任何函数并返回防反弹版本。

您应该能够使用滚动回调函数,并将其替换为_.debounce(function(){ ... your code ... }, 100)

如果您对实际的实现感兴趣,那么源代码非常简洁。

对我来说很好的是以下代码:

setupPaginationOnScroll: function() {
    var self = this;
    var loadNextPageIfNotLoadingThrottled = _.throttle(function() {
        if ( !self.isLastPageLoading() ) {
            self.loadNextPage()
        }
    },1000);
    this.onScrollbarNearBottom(loadNextPageIfNotLoadingThrottled);
},

您会注意到,我使用了throttle而不是debounce,当有一个挂起的请求时,我只是忽略滚动事件

这部分也会引起你的兴趣:

onScrollbarNearBottom: function(callback) {
    var target = this.getDOMNode();
    $(target).scroll(function(e) {
        if ( ScrollUtils.isScrollbarNearBottom(target) ) {
            callback(e);
        }
    });
}

module.exports = {
    debug: false,
    /**
     * We consider someone is near the bottom if he has scrolled more than 90%
     */
    scrollNearThreshold: 90,

    /**
     * Useful function to detect for exemple when to load more content (ie another page)
     * if the user has almost scrolled to the bottom
     *
     * @return {boolean}
     */
    isWindowScrollbarNearBottom: function() {
        return this.isScrollbarNearBottom(window);
    },
    isScrollbarNearBottom: function(scrollableElementSelector) {
        return this.getScrollPercentage(scrollableElementSelector) > this.scrollNearThreshold;
    },

    /**
     * Returns the percentage of scroll in a given container.
     * If the scrollbar is at the beginning it should return 0.
     * If the scrollbar is at the end it should return 100 (almost :s)
     *
     * See http://stackoverflow.com/questions/22867584/get-scroll-percentage-in-a-dom-container
     * For an unknown reason it sometimes returns a value > 100 (like 103 if you are at the bottom)
     * It is not very precise but at least it should work rather well for most usecases.
     *
     * @return {number}
     */
    getScrollPercentage: function(scrollableElementSelector) {
        var scrollableElement = $(scrollableElementSelector);
        // This is the number of hidden pixels of the scrollable element inside its container
        var hiddenHeigth;
        if ( scrollableElementSelector === window ) {
            hiddenHeigth = $(document).height() - $(window).height();
        } else {
            hiddenHeigth = scrollableElement[0].scrollHeight - scrollableElement.outerHeight();
        }
        // This is the number of scrolled pixels
        var scrolledHeight = scrollableElement.scrollTop();
        //if ( hiddenHeigth < scrolledHeight ) {
        //throw new Error("hiddenHeigth "+hiddenHeigth+" < scrolledHeight " +scrolledHeight + " -> Impossible unless you didn't use this function correctly");
        //}
        var scrollPercent = ( scrolledHeight / hiddenHeigth ) * 100;
        if ( this.debug ) {
            console.debug("hiddenHeigth=",hiddenHeigth,"scrolledHeight=",scrolledHeight,"scrollPercent=",scrollPercent);
        }
        return scrollPercent;
    }
}