Прокрутка события стрельбы слишком много раз. Я только хочу, чтобы он срабатывал максимум, скажем, один раз в секунду

У меня есть страница с "бесконечным прокруткой". Он вычисляет разницу между концом страницы и текущей страницей и загружает больше контента, если эта разница достаточно мала. Код такой же, как при использовании jQuery:

$(window).on('scroll', function() {
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
        # load more content via ajax
}

Теперь проблема заключается в том, что каждый раз, когда я прокручиваю, это событие срабатывает несколько раз за прокрутку. Я хотел бы стрелять максимум каждые миллисекунды. Как мне это сделать?

Ответ 1

Посмотрите метод "throttle" библиотеки Underscore.js.

http://underscorejs.org/#throttle

Пример, который он дает, - это именно то, о чем вы спрашиваете, - ограничение того, как часто вам приходится обрабатывать события прокрутки.

Ответ 2

Один из способов решения этой проблемы - определить временной интервал и обрабатывать только событие прокрутки один раз в течение этого интервала времени. Если за этот промежуток времени приходит более одного события прокрутки, вы игнорируете его и обрабатываете его только тогда, когда этот промежуток времени прошел.

var scrollTimer, lastScrollFireTime = 0;

$(window).on('scroll', function() {

    var minScrollTime = 100;
    var now = new Date().getTime();

    function processScroll() {
        console.log(new Date().getTime().toString());
    }

    if (!scrollTimer) {
        if (now - lastScrollFireTime > (3 * minScrollTime)) {
            processScroll();   // fire immediately on first scroll
            lastScrollFireTime = now;
        }
        scrollTimer = setTimeout(function() {
            scrollTimer = null;
            lastScrollFireTime = new Date().getTime();
            processScroll();
        }, minScrollTime);
    }
});

Это приведет к немедленному запуску первого события прокрутки, а затем вы получите событие прокрутки примерно один раз каждые 100 мс, пока полоса прокрутки перемещается, а затем одно последнее событие после того, как полоса прокрутки перестанет двигаться. Вы можете отрегулировать частоту события, изменив аргумент на setTimeout (в настоящее время установлено значение 100).

Здесь есть демо: http://jsfiddle.net/jfriend00/EBEqZ/, который вам нужно открыть окно консоли отладки, начать перемещение полосы прокрутки в окне содержимого и затем просмотрите время каждого события прокрутки в окне консоли отладки. В моей версии Chrome они устанавливаются на минимальное расстояние 100 мс, и они, кажется, происходят каждые 100-200 м.

Ответ 3

Существует прекрасное объяснение от Джона Ресига, создателя jQuery, чтобы решить эту ситуацию.

var outerPane = $details.find(".details-pane-outer"),
    didScroll = false;

$(window).scroll(function() {
    didScroll = true;
});

setInterval(function() {
    if ( didScroll ) {
        didScroll = false;
        // Check your page position and then
        // Load in more results
    }
}, 250);

Источник: http://ejohn.org/blog/learning-from-twitter/

Ответ 4

var isWorking = 0;

$(window).on('scroll', function()
{
    if(isWorking==0)  
    {
         isWorking=1;
         if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
         # load more content via ajax
         setTimeout(function(){isWorking=0},1000);
    }
}

Ответ 5

var now = new Date().getTime();
$(window).scroll( function () {
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
    {
        if (new Date().getTime() - now > 1000)
        {
            console.log("Task executed once per second");
            now = new Date().getTime();
        }
    }
});

Или

Вы можете использовать Throttling fonction calls: throttling-function-calls

function throttle(fn, threshhold, scope) {
  threshhold || (threshhold = 250);
  var last,
      deferTimer;
  return function () {
    var context = scope || this;

    var now = +new Date,
        args = arguments;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
}

Вы можете называть это следующим образом:

$('body').on('mousemove', throttle(function (event) {
  console.log('tick');
}, 1000));

Ответ 6

Вот решение, которое не требует использования дополнительной JS-библиотеки или плагина, целью которой является простота. Это может быть не так эффективно, как другие реализации, но это определенно шаг вперед от запуска основного события каждый раз, когда вы прокручиваете.

Это было взято из этого сообщения в блоге Дэнни Ван Кутен. Что я использовал для задержки моих onscroll() событий для моей кнопки "back-to-top" в моем блоге.

var timer;
$(window).scroll(function() {
    if(timer) {
        window.clearTimeout(timer);
    }
    timer = window.setTimeout(function() {
       // actual code here. Your call back function.
    console.log( "Firing!" );
    }, 100);
});

Вы также можете улучшить производительность, вытеснив переменные из функции обратного вызова, чтобы избежать ненужных пересчетов, например, значение $(window).height() или высота некоторого статического элемента div, который не изменится после загрузки страницы.

Вот пример, который адаптирован из моего варианта использования.

var scrollHeight = $("#main-element").height(); //never changes, no need to recalculate.
$(window).on('scroll', function() {
    if (timer) 
        window.clearTimeout(timer);
    timer = window.setTimeout(function() {
        var scrollPosition = $(window).height() + $(window).scrollTop();    
        if ($(window).scrollTop() < 500)
            $(".toggle").fadeIn(800);
        else 
            $(".toggle").fadeOut(800);
    }, 150); //only fire every 150 ms.
});

Это ограничивает действительную функцию только для выполнения каждые 150 мс, иначе reset таймер возвращается к 0, если 150 мс не прошло. Подстройте значение, соответствующее тому, что вам нужно.

Ответ 7

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