Heim > Artikel > Web-Frontend > JavaScript-Thema drei: Anti-Shake
Inhaltsverzeichnis
Javascript-Video-Tutorial)
1. Warum Anti-Shake. benötigt wirdHochfrequenz Funktionsoperationen kann schlechte Auswirkungen haben
Wir schreiben einen Index .html-Datei:
<meta> <meta> <meta> <title>Document</title> <title>debounce</title> <style> #wrapper { width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px; } </style> <p></p> <script> var count = 1; var op = document.getElementById("wrapper"); function getUserAction() { op.innerHTML = count++; } op.onmousemove = getUserAction; </script>
Wird beim Schieben von links nach rechts ausgelöst. Die Funktion getUserAction
wurde fast 100 Mal verwendet! Siehe das folgende Gif:
getUserAction
函数!看如下Gif:
因为这个例子很简单,所以浏览器完全反应的过来,但假设:
这种在一瞬间(短时间内)对浏览器或服务器造成了过多压力的交互就需要进行优化了,为了解决这个问题,一般有两种解决方案:
他们的目的都是:降低一个函数的触发频率,以提高性能或避免资源浪费。
二、防抖的原理
今天重点讲讲防抖的实现。
防抖的原理就是:你尽管触发事件,但是我一定在事件触发n秒无操作后
才执行。举个例子:
我们规定3s
为防抖的标准,那么:
三、自己实现一个防抖
我们根据上一节提到的核心思想,实现第一版代码:
function debounce(func, wait) { var timer; return function () { clearTimeout(timer) timer = setTimeout(func, wait); }}
如果我们要使用它,第一节的例子为例:
op.onmousemove = debounce(getUserAction, 2000);
此时大家可以再次测试一下,事件持续发生时,只有在完全停止2s后,才会触发事件:
写到这里,作为针对部分高频事件的需求来说,已经结束了。我们来看看他的效果:
大家都知道,dom节点在触发事件的时候,this指向它本身,本例中则指向op
,但是在本例中:我们看一下
var count = 1;var op = document.getElementById("op");function getUserAction() { op.innerHTML = count++; console.log('this', this); // 此时输出 Window...}op.onmousemove = debounce(getUserAction, 2000);function debounce(func, wait) { var timer; return function () { clearTimeout(timer) timer = setTimeout(func, wait); }}
毕竟经过了一层匿名函数的包裹,this已经指向了window,为了减少影响,我们尝试修正它
function debounce(func, wait) { var timer; return function () { var _this = this; // 记录当前this clearTimeout(timer) timer = setTimeout(function(){ func.apply(_this); //将 func的this改为_this }, wait); }}
解决的this指向问题,我们的函数仍然不够“完美”,JavaScript中,事件处理函数会提供event
对象,我们简称为e。
// 使用了 debouce 函数function getUserAction(e) { console.log(e); // undefined op.innerHTML = count++;};
为了保证它的原汁原味,我们再改第三版:
var count = 1;var op = document.getElementById("op");function getUserAction(e) { op.innerHTML = count++; console.log('e', e); // MouseEvent}op.onmousemove = debounce(getUserAction, 2000);function debounce(func, wait) { var timer; return function () { var _this = this; // 记录当前this var arg = arguments; // 记录参数 clearTimeout(timer) timer = setTimeout(function () { func.apply(_this, arg); //将 func的this改为_this }, wait); }}
到此为止,我们在尽可能保留Dom事件原有能力的情况下,给函数加上了防抖效果,它可以解决大部分我们日常开发的防抖问题,但我们需要更“完美”
四、防抖进阶
这个需求就是:
n
秒空白期n
秒空白期置后想想这个需求也是很有道理的嘛,那我们加个immediate
Es wird extrem häufig ausgelöst, 2000 Mal pro Minute, und erfordert viele Positionsberechnungen, DOM-Operationen usw.,
Es gibt Schnittstellenanforderungen. Die Ausführung einer einzelnen Funktion dauert lange, aber jede Funktion wird in sehr kurzen Abständen ausgelöst.Throttle Throttling Ihr Zweck ist:
Reduzieren Sie die Auslösehäufigkeit einer Funktion, um die Leistung zu verbessern oder Ressourcenverschwendung zu vermeiden.
🎜🎜🎜 2. Das Prinzip von Anti-Shake 🎜🎜🎜 Heute konzentrieren wir uns auf die Umsetzung von Anti-Shake. 🎜🎜Das Prinzip von Anti-Shake ist: Selbst wenn Sie ein Ereignis auslösen, werde ich es erst nachn Sekunden Inaktivität
nach Auslösung des Ereignisses ausführen. Zum Beispiel: 🎜🎜Wir legen 3s
als Standard für Anti-Shake fest, dann: 🎜🎜🎜🎜Drei. Implementieren Sie selbst einen Anti-Shake🎜🎜🎜3.1 Erste Version🎜🎜Wir haben die erste Version des Codes basierend auf den im vorherigen Abschnitt erwähnten Kernideen implementiert:🎜
function debounce(func, wait, immediate) { var timer; return function () { var _this = this; var args = arguments; if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时 if (immediate) { // 如果已经执行过,不再执行 var callNow = !timer; // 1. callNow 初始值是 true, 同步立即执行;随后 timer 才开始执行 timer = setTimeout(function(){ timer = null; // wait 期间,timer 是一个 ID 数字,所以 callNow 为 false,func 在此期间永远不会执行 }, wait) // wait 之后,timer 赋值 null,callNow 为 true,func 又开始立即执行。 if (callNow) func.apply(_this, args) } else { timer = setTimeout(function(){ func.apply(_this, args) }, wait); } }}🎜Wenn wir ihn verwenden möchten Nehmen Sie das Beispiel im ersten Abschnitt als Beispiel:🎜
function debounce(func, wait, immediate) { var timer; // 检查函数 if (typeof func !== 'function') { throw new TypeError('Expected a function'); } // 保证wait存在 wait = +wait || 0; const debounced = function () { var _this = this; var args = arguments; if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时 if (immediate) { // 如果已经执行过,不再执行 var callNow = !timer; // 如果不存在定时器,则callNow为true timer = setTimeout(function () { timer = null; // 为了保证之后的时效性,手动添加timer }, wait) // 因为不存在timer,证明是首次执行,所以直接调用 if (callNow) func.apply(_this, args) } else { timer = setTimeout(function () { func.apply(_this, args) }, wait); } } return debounced}🎜Zu diesem Zeitpunkt können Sie es erneut testen. Wenn das Ereignis weiterhin auftritt, wird das Ereignis erst nach 2 Sekunden vollständigem Stopp ausgelöst: 🎜🎜Hier geschrieben, Als Voraussetzung für einige Hochfrequenzereignisse ist es vorbei. Werfen wir einen Blick auf die Wirkung: 🎜🎜🎜🎜3.2 Zweite Ausgabe🎜🎜Jeder weiß, dass, wenn ein Dom-Knoten ein Ereignis auslöst, dieser auf sich selbst zeigt. In diesem Fall zeigt er auf
op
, aber in diesem Fall: Schauen wir uns das mal an 🎜 function debounce(func, wait, immediate) { var timer; // 检查函数 if (typeof func !== 'function') { throw new TypeError('Expected a function'); } // 保证wait存在 wait = +wait || 0; const debounced = function () { var _this = this; var args = arguments; if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时 if (immediate) { // 如果已经执行过,不再执行 var callNow = !timer; // 如果不存在定时器,则callNow为true timer = setTimeout(function () { timer = null; // 为了保证之后的时效性,手动添加timer }, wait) // 因为不存在timer,证明是首次执行,所以直接调用 if (callNow) func.apply(_this, args) } else { timer = setTimeout(function () { func.apply(_this, args) }, wait); } } const cancel = function(){ clearTimeout(timer); timer = null; } const pending = function(){ return timer !== undefined; } debounced.cancel = cancel; debounced.pending = pending; return debounced}🎜Nachdem es mit einer anonymen Funktion umschlossen wurde, zeigt dies bereits auf das Fenster. Um die Auswirkungen zu verringern, versuchen wir, dieses Zeigeproblem durch 🎜rrreee🎜Die dritte Ausgabe🎜🎜unsere Funktion zu beheben Immer noch nicht „perfekt“ genug. In JavaScript stellt die Ereignisbehandlungsfunktion das Objekt
event
bereit, das wir kurz e nennen. 🎜rrreee🎜Um die Authentizität zu gewährleisten, haben wir die dritte Version geändert: 🎜rrreee🎜Bisher haben wir der Funktion einen Anti-Shake-Effekt hinzugefügt und dabei die ursprünglichen Fähigkeiten des Dom-Events so weit wie möglich beibehalten Lösen Sie die meisten unserer täglichen Anti-Shake-Probleme in der Entwicklung, aber wir müssen „perfekter“ werden🎜🎜🎜🎜 4. Anti-Shake erweitert 🎜🎜🎜4.1 Sofort ausführen 🎜🎜Diese Anforderung ist: 🎜🎜🎜 Sofort ausführen 🎜 🎜Behalten Sie n
zweite Leerperiode bei. 🎜🎜 Setzen Sie die n
zweite Leerperiode nach hinten. 🎜🎜🎜Es ist sinnvoll, über diese Anforderung nachzudenken. Dann fügen wir immediate hinzu bestimmt, ob er sofort ausgeführt wird. 🎜rrreee🎜 Werfen wir einen Blick auf die Wirkung zu diesem Zeitpunkt: 🎜🎜🎜🎜🎜4.2 Einfache Überprüfung hinzufügen🎜rrreee🎜4.3 Abbruchereignismethode hinzufügen🎜🎜Wenn Sie das Anti-Shake-Ereignis abbrechen möchten, können wir so schreiben: 🎜rrree 🎜Schauen wir uns die Wirkung an: 🎜🎜🎜🎜🎜 Auch wenn diese einfache Anti-Shake-Methode in Ordnung ist, ist sie in der Tat nicht perfekt. Wenn Sie Verbesserungsvorschläge haben, hinterlassen Sie bitte eine Nachricht im Kommentarbereich 🎜<blockquote><p><strong>Verwandte kostenlose Lernempfehlungen: </strong><a href="https://www.php.cn/course/list/17.html" target="_blank" textvalue="javascript"><strong>Javascript</strong></a><strong>(Video)</strong></p></blockquote>
Das obige ist der detaillierte Inhalt vonJavaScript-Thema drei: Anti-Shake. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!