Maison > interface Web > js tutoriel > le corps du texte

Explication détaillée de la fonction de limitation JavaScript Throttle

黄舟
Libérer: 2017-03-07 14:35:47
original
1116 Les gens l'ont consulté

Dans les événements DOM du navigateur, certains événements seront déclenchés en continu avec les opérations de l'utilisateur. Par exemple : redimensionnez la fenêtre du navigateur (resize), faites défiler la page du navigateur (scroll) et déplacez la souris (mousemove). C'est-à-dire que lorsque l'utilisateur déclenche ces opérations du navigateur, si la méthode de traitement des événements correspondante est liée au script, cette méthode sera déclenchée en continu.

Ce n'est pas ce que nous voulons, car parfois si la méthode de traitement des événements est relativement volumineuse, le fonctionnement du DOM est compliqué et de tels événements sont déclenchés en continu, cela entraînera des pertes de performances et réduira l'expérience utilisateur (réponse de l'interface utilisateur est lent, le navigateur se bloque, etc.). De manière générale, nous ajouterons une logique d’exécution différée à l’événement correspondant.

Habituellement, nous utilisons le code suivant pour implémenter cette fonction :

var COUNT = 0;
function testFn() { console.log(COUNT++); }
// 浏览器resize的时候
// 1. 清除之前的计时器
// 2. 添加一个计时器让真正的函数testFn延后100毫秒触发
window.onresize = function () {
    var timer = null;
    clearTimeout(timer);

    timer = setTimeout(function() {
        testFn();
    }, 100);
};
Copier après la connexion

Les étudiants attentifs découvriront que le code ci-dessus est en fait faux. C'est un problème que les novices se poseront : La valeur de retour. de la fonction setTimeout doit être stockée dans une variable globale relative, sinon un nouveau timer sera généré à chaque redimensionnement, ce qui n'obtiendra pas l'effet que nous avons envoyé

Nous avons donc modifié le code :

var timer = null;
window.onresize = function () {
    clearTimeout(timer);
    timer = setTimeout(function() {
        testFn();
    }, 100);
};
Copier après la connexion

À l'heure actuelle, le code est normal, mais il y a un nouveau problème : une minuterie variable globale est générée. C'est ce que nous ne voulons pas voir. Si cette page a d'autres fonctions également appelées minuterie, différents codes entreront en conflit auparavant. Afin de résoudre ce problème, nous devons utiliser une fonctionnalité du langage JavaScript : fermeture fermetures. Les lecteurs ayant des connaissances pertinentes peuvent se rendre sur MDN pour en savoir plus. Le code modifié est le suivant :

/**
 * 函数节流方法
 * @param Function fn 延时调用函数
 * @param Number delay 延迟多长时间
 * @return Function 延迟执行的方法
 */
var throttle = function (fn, delay) {
    var timer = null;

    return function () {
        clearTimeout(timer);
        timer = setTimeout(function() {
            fn();
        }, delay);
    }
};
window.onresize = throttle(testFn, 200, 1000);
Copier après la connexion

Nous utilisons une fonction de fermeture (throttle throttling) pour mettre la minuterie à l'intérieur et renvoyer la fonction de traitement du retard, de sorte que la variable timer est invisible pour le monde extérieur, mais la variable timer est également accessible lorsque la fonction de retard interne est déclenchée.

Bien sûr, cette façon d'écrire est difficile à comprendre pour les novices. On peut changer la façon d'écrire pour la comprendre :

var throttle = function (fn, delay) {
    var timer = null;

    return function () {
        clearTimeout(timer);
        timer = setTimeout(function() {
            fn();
        }, delay);
    }
};

var f = throttle(testFn, 200);
window.onresize = function () {
    f();
};
Copier après la connexion

La principale chose à comprendre ici est : <🎜. >Throttle est La fonction renvoyée après l'appel est la vraie fonction qui doit être appelée lorsque onresize est déclenché

Maintenant, il semble que cette méthode soit proche de la perfection, mais ce n'est pas le cas en réalité utiliser. Par exemple :

Si l'utilisateur

redimensionne continuellement la fenêtre du navigateur, alors la fonction de traitement différé ne sera pas exécutée une seule fois

Donc nous un autre une fonction doit être ajoutée : lorsque l'utilisateur déclenche le redimensionnement, il doit

se déclencher au moins une fois dans un certain laps de temps Puisque c'est dans un certain laps de temps, alors cette condition de jugement peut prendre l'heure actuelle. millisecondes, à chaque fois Cet appel de fonction soustrait l'heure actuelle de l'heure du dernier appel, puis détermine si la différence est supérieure à une certaine période de temps , elle sera déclenchée directement. Sinon, la logique de retard de. le délai d'attente sera toujours utilisé.

Ce qu'il faut souligner dans le code suivant est :

  1. Le rôle de la variable précédente est similaire à celui du timer. Elles enregistrent toutes deux la dernière identification et. doit être une variable globale relative

  2. Si le flux logique suit la logique de "déclencher au moins une fois", alors l'appel de fonction doit être réinitialisé à l'heure actuelle, ce qui signifie simplement : par rapport à l'heure précédente de la prochaine fois En fait, c'est la pratique actuelle

/**
 * 函数节流方法
 * @param Function fn 延时调用函数
 * @param Number delay 延迟多长时间
 * @param Number atleast 至少多长时间触发一次
 * @return Function 延迟执行的方法
 */
var throttle = function (fn, delay, atleast) {
    var timer = null;
    var previous = null;

    return function () {
        var now = +new Date();

        if ( !previous ) previous = now;

        if ( now - previous > atleast ) {
            fn();
            // 重置上一次开始时间为本次结束时间
            previous = now;
        } else {
            clearTimeout(timer);
            timer = setTimeout(function() {
                fn();
            }, delay);
        }
    }
};
Copier après la connexion
:

On simule un scénario de throttling lorsqu'une fenêtre défile, c'est-à-dire que nous devons ralentir lorsque l'utilisateur fait défiler la page. Le flux exécute certaines méthodes, telles que le calcul de la position DOM et d'autres actions qui nécessitent une manipulation continue des éléments DOM

Le code complet est le suivant. :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>throttle</title>
</head>
<body>
    <p style="height:5000px">
        <p id="demo" style="position:fixed;"></p>
    </p>
    <script>
    var COUNT = 0, demo = document.getElementById(&#39;demo&#39;);
    function testFn() {demo.innerHTML += &#39;testFN 被调用了 &#39; + ++COUNT + &#39;次<br>&#39;;}

    var throttle = function (fn, delay, atleast) {
        var timer = null;
        var previous = null;

        return function () {
            var now = +new Date();

            if ( !previous ) previous = now;
            if ( atleast && now - previous > atleast ) {
                fn();
                // 重置上一次开始时间为本次结束时间
                previous = now;
                clearTimeout(timer);
            } else {
                clearTimeout(timer);
                timer = setTimeout(function() {
                    fn();
                    previous = null;
                }, delay);
            }
        }
    };
    window.onscroll = throttle(testFn, 200);
    // window.onscroll = throttle(testFn, 500, 1000);
    </script>
</body>
</html>
Copier après la connexion
Nous utilisons deux cas pour tester l'effet, en ajoutant respectivement au moins Déclencher le paramètre au moins et en n'ajoutant pas :

// case 1
window.onscroll = throttle(testFn, 200);
// case 2
window.onscroll = throttle(testFn, 200, 500);
Copier après la connexion

cas 1 se comporte comme suit : testFN ne sera pas appelé pendant le processus de défilement de la page (ne peut pas être arrêté), jusqu'à ce qu'il soit arrêté une fois, c'est-à-dire que le dernier setTimeout dans la manette est exécuté. la figure (voir le gif original) :

cas 2 se comporte comme suit : pendant le processus de défilement de la page (ne peut pas être arrêté), testFN sera exécuté avec un délai de 500 ms pour la première fois (à partir d'au moins la logique de retard), puis exécuté au moins toutes les 500 ms. L'effet est comme indiqué sur la figure

Donc. Jusqu'à présent, l'effet que nous souhaitons obtenir est pratiquement achevé. Les lecteurs peuvent découvrir par eux-mêmes certaines optimisations auxiliaires ultérieures, telles que : la fonction vers laquelle pointe, le stockage de la valeur de retour, etc.

Citation

  1. Code de test http://jsbin.com/tanuxegija/edit

  2. Code de la version complète http:/ /jsbin.com/jigozuvuko

  3. Debounce VS throttle https://github.com/dcorb/debounce-throttle

Ce qui précède est une explication détaillée de la fonction de limitation JavaScript Throttle. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal