Heim  >  Artikel  >  Web-Frontend  >  JavaScript-Thema drei: Anti-Shake

JavaScript-Thema drei: Anti-Shake

coldplay.xixi
coldplay.xixinach vorne
2021-03-04 09:56:003160Durchsuche

JavaScript-Thema drei: Anti-Shake

Inhaltsverzeichnis

  • 1. Das Prinzip von Anti-Shake
  • 3. Die einfache Implementierung von Anti-Shake
  • . Shake
  • Geschrieben am Ende
(Verwandte kostenlose Lernempfehlungen:

Javascript-Video-Tutorial)

1. Warum Anti-Shake. benötigt wird

Hochfrequenz Funktionsoperationen kann schlechte Auswirkungen haben
  • wie: Größe ändern, scrollen, Maus nach unten, Maus bewegen, Tasten nach oben, Tasten nach unten ...
  • Zu diesem Zweck geben wir einen Beispielcode, um zu verstehen, wie das Ereignis häufig ausgelöst wird:

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:

Bildbeschreibung hier einfügengetUserAction 函数!看如下Gif:

JavaScript-Thema drei: Anti-Shake

因为这个例子很简单,所以浏览器完全反应的过来,但假设:

  • 它的触发频次极高,1分钟2000次,且涉及到大量的位置计算、DOM 操作等工作,
  • 存在接口请求,单个函数执行时间较长,但每个函数触发的间隔很近。

这种在一瞬间(短时间内)对浏览器或服务器造成了过多压力的交互就需要进行优化了,为了解决这个问题,一般有两种解决方案:

  • debounce 防抖
  • throttle 节流

他们的目的都是:降低一个函数的触发频率,以提高性能或避免资源浪费。

二、防抖的原理

今天重点讲讲防抖的实现。

防抖的原理就是:你尽管触发事件,但是我一定在事件触发n秒无操作后才执行。举个例子:

我们规定3s为防抖的标准,那么:

  1. 第一次要求执行事件 - 此时倒计时3s
  2. 倒计时2s
  3. 倒计时1s
  4. 0.5s时事件再次被触发 - 此时倒计时3s
  5. …3s内无事发生
  6. 执行事件,共用了5.5s

JavaScript-Thema drei: Anti-Shake

三、自己实现一个防抖

3.1 第一版

我们根据上一节提到的核心思想,实现第一版代码:

function debounce(func, wait) {
    var timer;
    return function () {
        clearTimeout(timer)
        timer = setTimeout(func, wait);
    }}

如果我们要使用它,第一节的例子为例:

op.onmousemove = debounce(getUserAction, 2000);

此时大家可以再次测试一下,事件持续发生时,只有在完全停止2s后,才会触发事件:

写到这里,作为针对部分高频事件的需求来说,已经结束了。我们来看看他的效果:

JavaScript-Thema drei: Anti-Shake

3.2 第二版

大家都知道,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事件原有能力的情况下,给函数加上了防抖效果,它可以解决大部分我们日常开发的防抖问题,但我们需要更“完美”

JavaScript-Thema drei: Anti-Shake

四、防抖进阶

4.1 立即执行

这个需求就是:

  • 立即执行
  • 保持n秒空白期
  • n秒空白期置后

想想这个需求也是很有道理的嘛,那我们加个immediate

Da dieses Beispiel sehr einfach ist, kann der Browser vollständig reagieren, aber angenommen:

Es wird extrem häufig ausgelöst, 2000 Mal pro Minute, und erfordert viele Positionsberechnungen, DOM-Operationen usw., JavaScript-Thema drei: Anti-Shake

Es gibt Schnittstellenanforderungen. Die Ausführung einer einzelnen Funktion dauert lange, aber jede Funktion wird in sehr kurzen Abständen ausgelöst.

Diese Art der Interaktion, die den Browser oder Server in kurzer Zeit zu stark belastet, muss optimiert werden. Um dieses Problem zu lösen, gibt es im Allgemeinen zwei Lösungen:

Debounce Anti-Shake

Throttle Throttling

JavaScript-Thema drei: Anti-Shake

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 nach n Sekunden Inaktivität nach Auslösung des Ereignisses ausführen. Zum Beispiel: 🎜🎜Wir legen 3s als Standard für Anti-Shake fest, dann: 🎜
    🎜Das erste Mal, dass ein Ereignis angefordert wird – der Countdown beträgt zu diesem Zeitpunkt 3s🎜🎜Der Countdown ist 2s🎜🎜Der Countdown beträgt 1s🎜🎜 Das Ereignis wird erneut bei 0,5s ausgelöst – zu diesem Zeitpunkt beträgt der Countdown 3s🎜🎜... innerhalb von 3s passiert nichts🎜🎜Das Ereignis wird ausgeführt und teilt sich 5,5s🎜

JavaScript-Thema drei: Anti-Shake🎜🎜🎜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: 🎜🎜Bildbeschreibung hier einfügen🎜🎜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🎜

JavaScript-Thema drei: Anti-Shake🎜🎜🎜 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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen