Дросселирование/устранение дребезга бесконечной прокрутки Javascript

У меня есть эта функция бесконечной прокрутки, настроенная на нескольких моих страницах. Он отлично работает, но вызов 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

РЕДАКТИРОВАТЬ:

Я загрузил подчеркивание и добавил функцию устранения дребезга, но теперь вызов Ajax, похоже, вообще не работает. Даже если бы я не установил немедленное значение true, оно должно выполняться довольно быстро после прекращения прокрутки, но оно не выполняется вообще.


person jaimerump    schedule 13.07.2012    source источник


Ответы (3)


В библиотеке Underscore есть методы для этого:

Вы, вероятно, хотите _.debounce. Если вы не хотите добавлять Underscore в качестве дополнительной зависимости, вы можете создать автономный метод из источника для нужного вам метода.

person nrabinowitz    schedule 13.07.2012

Взгляните на подчеркивание. У них есть отличная маленькая обертка для устранения дребезга, которая может принимать любую функцию и возвращать ее версию.

Вы должны иметь возможность взять эту функцию обратного вызова прокрутки и заменить ее на _.debounce(function(){ ... your code ... }, 100).

Если вам интересна реальная реализация, исходный код хорош и лаконичен.

person Koobz    schedule 13.07.2012

Что отлично работает для меня, так это следующий код:

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

Вы заметите, что я использую дросселирование, а не устранение дребезга, и когда есть ожидающий запрос, я просто игнорирую событие прокрутки.

Эта часть также может вас заинтересовать:

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;
    }

}
person Sebastien Lorber    schedule 17.07.2014