Javascript setInterval und `this`-Lösung

Lesezeit: 5 Minuten

Ich muss zugreifen this Von meinem setInterval Handler

prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        this.intervalID = setInterval(this.retrieve_rate, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        ajax.onload = function()
        {
            // access prefs here
        }
    }

Wie kann ich auf this.prefs in zugreifen ajax.onload ?

  • Um eine gute Antwort mit 3 Lösungen zu sehen, überprüfen Sie dies: stackoverflow.com/a/7890978/2803565

    – S. Serpooshan

    25. Juli 2021 um 5:25 Uhr


this.intervalID = setInterval(this.retrieve_rate.bind(this), this.INTERVAL);

  • Dies ist die richtige Lösung. Die akzeptierte Lösung scheint unnötig mehr Code zu erfordern.

    – Nick

    22. Mai 2014 um 23:37 Uhr

  • Aber diese Methode hat einen Nachteil. Höchstwahrscheinlich funktioniert es nicht mit älteren Versionen von IE

    – Nechin

    11. Juni 2014 um 12:25 Uhr

  • @Nechehin Bemerkenswert. Aber es ist immer noch eine viel sauberere Lösung.

    – Konnorbode

    11. März 2015 um 0:10 Uhr


  • Es wird seit IE9 unterstützt, also ist es eine saubere Lösung für mich.

    – barbara.post

    20. April 2015 um 8:37 Uhr

  • Wenn Sie Unterstützung für IE8 benötigen und Sie verwenden Unterstrich.jsDu könntest benutzen _.bind: this.intervalID = setInterval(_.bind(this.retrieve_rate, this), this.INTERVAL);

    – Gfullam

    21. August 2015 um 15:44 Uhr


Javascript setInterval und this Losung
AnthonyWJones

Die Zeile setInterval sollte so aussehen:

 this.intervalID = setInterval(
     (function(self) {         //Self-executing func which takes 'this' as self
         return function() {   //Return a function in the context of 'self'
             self.retrieve_rate(); //Thing you wanted to run as non-window 'this'
         }
     })(this),
     this.INTERVAL     //normal interval, 'this' scope not impacted here.
 ); 

Bearbeiten: Das gleiche Prinzip gilt für die ” onload “. In diesem Fall ist es üblich, dass der “äußere” Code wenig tut, er richtet nur die Anfrage ein und sendet sie dann. In diesem Fall ist der zusätzliche Overhead einer zusätzlichen Funktion wie im obigen Code unnötig. Ihre retrieve_rate sollte besser aussehen so was:-

retrieve_rate : function()
{
    var self = this;
    var ajax = new XMLHttpRequest();
    ajax.open('GET', 'http://xyz.com', true);
    ajax.onreadystatechanged= function()
    {
        if (ajax.readyState == 4 && ajax.status == 200)
        {
            // prefs available as self.prefs
        }
    }
    ajax.send(null);
}

  • Ich wollte das ursprünglich tun, aber dann erinnerte ich mich, dass dieses Muster wirklich am nützlichsten für Schleifen ist.

    – Matthäus Flaschen

    1. Mai 2010 um 8:26 Uhr

  • @Matthew Flaschen: Es ist für dieses Szenario genauso nützlich wie für Schleifen.

    – Andi E

    1. Mai 2010 um 9:51 Uhr

  • @Anthony: also der Trick mit self ist hier die einzige Möglichkeit? Können Sie bestätigen, dass die Lösung von Matthew nicht funktioniert?

    – Pablo

    1. Mai 2010 um 13:03 Uhr

  • @Michael: Zunächst einmal ist es kein “Trick”, sondern nur, wie die Dinge in Javascript funktionieren. Matthews Antwort zum Zeitpunkt des Schreibens dieses Kommentars funktioniert nicht. Es gab eine frühere Version davon, die vielleicht funktioniert hätte, aber sie beinhaltete das Passieren this als Parameter, was unnötig und umständlich war (jeder Aufrufer von retrieve_rate hätte diese unnötige Sonderanforderung gewusst).

    – Anthony W Jones

    1. Mai 2010 um 19:26 Uhr

  • Vorbeigehen this als Argument für die (function(self){...})(this) in setInterval hat bei mir nicht funktioniert, da die Funktion sofort ausgeführt wird, anstatt verzögert zu werden. Die Lösung von @Joel Fillmore funktioniert für mich

    – Mensch

    21. Januar 2013 um 18:59 Uhr

1646245507 954 Javascript setInterval und this Losung
Joel Fillmore

Das Standardverhalten von setInterval ist die Bindung an den globalen Kontext. Sie können eine Memberfunktion aufrufen, indem Sie eine Kopie des aktuellen Kontexts speichern. Innerhalb von retrieve_rate die this Variable wird korrekt an den ursprünglichen Kontext gebunden. So würde Ihr Code aussehen:

var self = this;
this.intervalID = setInterval(
    function() { self.retrieve_rate(); },
    this.INTERVAL);

Bonus-Tipp: Für eine einfache Funktionsreferenz (im Gegensatz zu einer Objektreferenz mit einer Member-Funktion) können Sie den Kontext mithilfe von JavaScript ändern call oder apply Methoden.

  • Das hat bei mir funktioniert, der Aufruf zum ‘Anrufen’ scheint jedoch nicht erforderlich zu sein. Der Kontext von retrieve_rate sollte standardmäßig auf self gesetzt werden, da er als Member-Funktion aufgerufen wird.

    – Drendel

    7. Februar 2012 um 12:47 Uhr

  • @Dreendle – Sie haben Recht, ich erinnerte mich, dass ich dies für eine Callback-Funktionsreferenz gelöst hatte, wo es benötigt wurde. Ich habe die Antwort korrigiert, danke!

    – Joel Fillmore

    8. Februar 2012 um 16:43 Uhr

window.setInterval(function(){console.log(this)}.bind(this), 100)

das ist legal in javascript und spart viel code 🙂

Dies wäre die sauberste Lösung, da Sie die meiste Zeit diesen Kontext für Ihre aufeinanderfolgenden Methodenaufrufe tatsächlich wechseln möchten:

Auch ist es einfacher, das Konzept von zu begreifen.

    // store scope reference for our delegating method
    var that = this;
    setInterval(function() {
        // this would be changed here because of method scope, 
        // but we still have a reference to that
        OURMETHODNAME.call(that);
    }, 200);

Javascript setInterval und this Losung
gaetanoM

Bei modernen Browsern erlaubt die Methode setInterval zusätzliche Parameter, die nach Ablauf des Timers an die durch func angegebene Funktion durchgereicht werden.

var intervalID = scope.setInterval(Funktion, Verzögerung[, param1, param2, …]);

Eine mögliche Lösung kann daher sein:

this.intervalID = setInterval(function (self) {
        self.retrieve_rate();
    }, this.INTERVAL, this);

Eine Demo:

var timerId;
document.querySelector('#clickMe').addEventListener('click', function(e) {
    timerId = setInterval(function (self) {
        self.textContent = self.textContent.slice(0, -1);
        if (self.textContent.length == 0) {
            clearInterval(timerId);
            self.textContent="end..";
        }
    }, 250, this);
})
<button id="clickMe">ClickMe</button>

prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        var context = this;
        this.intervalID = setInterval(function()
                                      {
                                          context.retrieve_rate();
                                      }, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        var context = this;
        ajax.onload = function()
        {
            // access prefs using context.
            // e.g. context.prefs
        }
    }

  • this innerhalb der übergebenen Funktion setInterval, bezieht sich auf das globale Objekt. Hast du gemeint context.retrieve_rate anstatt this.retrieve_rate ?

    – Christian C. Salvado

    1. Mai 2010 um 8:11 Uhr

  • Dies hat sich in die richtige Richtung entwickelt, der Kontext muss jedoch nicht als Parameter übergeben werden.

    – Anthony W Jones

    1. Mai 2010 um 8:16 Uhr

  • @Matthew, Anthony Also, wie greife ich von Onload darauf zu? Versucht this.prefs, aber hat nicht funktioniert …

    – Pablo

    1. Mai 2010 um 8:19 Uhr

  • Gern geschehen, Matthew, brauchst du übrigens nicht zu benutzen call, context.retrieve_rate() reicht, da hast du a Basisobjekt (context.)

    – Christian C. Salvado

    1. Mai 2010 um 8:19 Uhr

  • Nochmals vielen Dank, @Anthony und @CMS. 🙂 Es ist leicht, unnötig “clever” zu werden, wenn Closures im Spiel sind.

    – Matthäus Flaschen

    1. Mai 2010 um 8:24 Uhr

914870cookie-checkJavascript setInterval und `this`-Lösung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy