La limitation des fonctions, en termes simples, signifie qu'une fonction ne peut pas être appelée en continu dans un court intervalle de temps. Ce n'est que lorsque l'intervalle de temps que vous spécifiez s'est écoulé depuis la dernière exécution de la fonction que l'appel de fonction suivant peut être effectué.
Le principe de la limitation des fonctions est assez simple, je suppose que tout le monde y a pensé, c'est le timer. Lorsque je déclenche une heure, je règle d'abord Timeout pour retarder l'événement pendant un certain temps, puis je l'exécute à nouveau dans cet intervalle de temps, nous effaçons le minuteur d'origine, puis définissons Timeout un nouveau minuteur pour retarder l'exécution pendant un certain temps. ., c'est tout.
Les scénarios suivants sont souvent déclenchés par des événements fréquents, de sorte que les opérations DOM, le chargement des ressources et d'autres activités lourdes sont fréquemment effectués, entraînant des pauses dans l'interface utilisateur ou même des plantages du navigateur.
1. Les événements de redimensionnement et de défilement de l'objet fenêtre
2. L'événement mousemove lors du glisser
3. mousedown, événements keydown
4. Saisie de texte, événements keyup automatiquement complétés
En fait, pour les événements de redimensionnement de fenêtre, l'exigence réelle est principalement d'arrêter de changer la taille n millisecondes plus tard Effectuer un traitement ultérieur alors que la plupart des autres événements nécessitent un traitement ultérieur à une certaine fréquence. En réponse à ces deux besoins, deux solutions, anti-rebond et throttle, ont vu le jour.
l'accélérateur et l'anti-rebond sont deux solutions pour résoudre le problème de l'inadéquation des vitesses de requête et de réponse. La différence entre les deux réside dans le choix de stratégies différentes.
accélérateur Exécuter la fonction à intervalles de temps égaux.
Si l'événement anti-rebond est déclenché à nouveau dans l'intervalle de temps t, le temporisateur sera redémarré et la fonction ne sera exécutée que lorsque le temps d'arrêt sera supérieur ou égal à t.
1. Implémentation simple de la fonction d'accélérateur
function throttle(fn, threshhold, scope) { threshhold || (threshhold = 250); var last, timer; return function () { var context = scope || this; var now = +new Date(), args = arguments; if (last && now - last + threshhold < 0) { // hold on to it clearTimeout(deferTimer); timer = setTimeout(function () { last = now; fn.apply(context, args); }, threshhold); } else { last = now; fn.apply(context, args); } };}
Méthode d'appel
$('body').on('mousemove', throttle(function (event) { console.log('tick'); }, 1000));
2. 🎜>Méthode d'appel
function debounce(fn, delay) { var timer = null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); };}
3. Implémentation simple de l'encapsulation
$('input.username').keypress(debounce(function (event) { // do the Ajax request }, 250));
Résumé : Ces deux méthodes conviennent à certains événements qui seront déclenchés à plusieurs reprises, tels que : mousemove, keydown, keyup, appui sur une touche, défilement, etc.
Si vous liez uniquement des événements natifs sans les contrôler, le navigateur se bloquera et l'expérience utilisateur sera médiocre. Afin d'améliorer les performances de js, il est recommandé d'utiliser la limitation de fonction ou l'anti-rebond de fonction pour contrôler lors de l'utilisation des événements ci-dessus et similaires./** * throttle * @param fn, wait, debounce */var throttle = function ( fn, wait, debounce ) { var timer = null, // 定时器 t_last = null, // 上次设置的时间 context, // 上下文 args, // 参数 diff; // 时间差 return funciton () { var curr = + new Date(); var context = this, args = arguments; clearTimeout( timer ); if ( debounce ) { // 如果是debounce timer = setTimeout( function () { fn.apply( context, args ); }, wait ); } else { // 如果是throttle if ( !t_last ) t_last = curr; if ( curr - t_last >= wait ) { fn.apply( context, wait ); context = wait = null; } } }}/** * debounce * @param fn, wait */var debounce = function ( fn, wait ) { return throttle( fn, wait, true ); }
4. Analyse du code source liée au soulignement v1.7.0
1.Fonction _.throttle
Comme le montre le. ci-dessus, le trait de soulignement considère les situations les plus courantes : options.leading :
_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; // 定时器 var previous = 0; // 上次触发的时间 if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); // 第一次是否执行 if (!previous && options.leading === false) previous = now; // 这里引入了一个remaining的概念:还剩多长时间执行事件 var remaining = wait - (now - previous); context = this; args = arguments; // remaining <= 0 考虑到事件停止后重新触发或者 // 正好相差wait的时候,这些情况下,会立即触发事件 // remaining > wait 没有考虑到相应场景 // 因为now-previous永远都是正值,且不为0,那么 // remaining就会一直比wait小,没有大于wait的情况 // 估计是保险起见吧,这种情况也是立即执行 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; // 是否跟踪 } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; };};
S'il faut exécuter pour la première fois. La valeur par défaut est true, ce qui signifie qu'il sera exécuté pour la première fois. } désactive la première exécution des options trailing : s'il faut exécuter la dernière fois, la valeur par défaut est true, ce qui signifie qu'elle sera exécutée pour la dernière fois, et passer {trailing : false} signifie qu'elle ne sera pas exécutée pour la dernière fois. la dernière fois. Ce qu'on appelle s'il faut exécuter pour la première fois signifie s'il faut déclencher l'événement en premier lorsque l'événement est déclenché pour la première fois. Si si cela est nécessaire, alors précédent = 0 et le reste est une valeur négative, la fonction est appelée immédiatement. .La soi-disant s'il faut exécuter la dernière fois est la dernière fois que cette méthode est déclenchée après la fin de l'événement. S'il doit être exécuté, définissez le minuteur, c'est-à-dire qu'il sera exécuté une fois l'événement terminé. remianing > wait indique que l'heure du client a été modifiée.
Je pense que la chose merveilleuse à propos de _.debounce est qu'elle démarre le minuteur de manière récursive au lieu d'ajuster le délai d'appel de la fonction func en appelant clearTimeout mettre en œuvre.
_.debounce = function(func, wait, immediate) { // immediate默认为false var timeout, args, context, timestamp, result; var later = function() { // 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); // 第一次调用该方法时,且immediate为true,则调用func函数 var callNow = immediate && !timeout; // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数 if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; };};