69 votes

L'événement Scroll se déclenche trop souvent. Je veux qu'il se déclenche au maximum, disons, une fois par seconde.

J'ai une page avec "infinite scroll". Elle calcule la différence entre la fin de la page et la page actuelle et charge plus de contenu si cette différence est suffisamment faible. Le code est quelque chose comme ceci en utilisant jQuery :

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

Le problème est qu'à chaque fois que je fais défiler la page, cet événement se déclenche plusieurs fois par défilement. Je voudrais qu'il se déclenche au maximum toutes les x millisecondes. Comment faire ?

49voto

nicholaides Points 7859

Consultez la méthode "throttle" de la bibliothèque Underscore.js.

http://underscorejs.org/#throttle

L'exemple qu'il donne correspond exactement à votre question : limiter la fréquence à laquelle vous devez traiter les événements de défilement.

3 votes

Une bibliothèque assez impressionnante, mais j'essaie d'éviter toute dépendance.

29 votes

Regardez le code source de underscore (qui est formidablement documenté) et sortez les gaz.

1 votes

45voto

jfriend00 Points 152127

Une façon de résoudre ce problème est de définir un intervalle de temps et de ne traiter un événement de défilement qu'une fois dans cet intervalle de temps. Si plusieurs événements de défilement surviennent pendant cet intervalle de temps, vous les ignorez et ne les traitez qu'une fois cet intervalle écoulé.

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

Cela déclenchera immédiatement le premier événement de défilement, puis vous obtiendrez un événement de défilement environ toutes les 100 ms pendant que la barre de défilement est déplacée, puis un événement final après que la barre de défilement a cessé de se déplacer. Vous pouvez ajuster la fréquence de l'événement en modifiant l'argument de la fonction setTimeout (ce qui est actuellement fixé à 100).

Il y a une démo ici : http://jsfiddle.net/jfriend00/EBEqZ/ Vous devez ouvrir une fenêtre de console de débogage, commencer à déplacer la barre de défilement dans la fenêtre de contenu, puis observer l'heure de chaque événement de défilement dans la fenêtre de console de débogage. Dans ma version de Chrome, l'espacement minimal est de 100 ms et les événements semblent se produire toutes les 100 à 200 ms.

15voto

HolloW Points 353

Il existe une explication intéressante de John Resig, le créateur de jQuery, pour résoudre cette situation.

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

La source : http://ejohn.org/blog/learning-from-twitter/

10voto

Alan Kuras Points 592
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);
    }
}

0 votes

J'espère que ça marche, je ne l'ai pas testé, en gros ça lance chaque scroll mais si une autre copie est en cours d'exécution ça ne fait rien, sinon ça attend xxx milisecondes et ça fait le travail.

0 votes

Eeeeck. Vous ne pouvez pas utiliser une fonction de sommeil comme ça en javascript. Cela va bloquer le navigateur pendant le sommeil. Javascript est single threaded et bloque le navigateur. Vous ne pouvez tout simplement pas écrire du code javascript comme ça.

1 votes

Remplacez cela sleep con setTimeout(function(){isWorking=0},1000) et cela devrait fonctionner.

10voto

A. Morel Points 1115
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();
        }
    }
});

O

Vous pouvez utiliser les appels de fonction Throttling : appels à la fonction d'étranglement

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

Vous pouvez l'appeler comme ça :

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

2 votes

Veuillez ajouter des commentaires et une description à ce code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X