setInterval метод не работает [дубликат]

56
задан Pablo 1 May 2010 в 09:01
поделиться

8 ответов

Строка setInterval должна выглядеть так: -

 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.
 ); 

Изменить: тот же принцип применяется к «onload». В этом случае его общий для «внешнего» кода делать мало, он просто устанавливает запрос, а затем отправляет его. В этом случае дополнительные накладные расходы дополнительные функции, как в приведенном выше коде, не нужны. Ваш retrieve_rate должен выглядеть следующим образом: -

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);
}
81
ответ дан Incognito 29 August 2018 в 00:19
поделиться
  • 1
    Сначала я собирался сделать это, но потом я вспомнил, что этот шаблон действительно полезен для циклов. – Matthew Flaschen 1 May 2010 в 09:26
  • 2
    @Matthew Flaschen: Это так же полезно для этого сценария, как и для циклов. – Andy E 1 May 2010 в 10:51
  • 3
    @ Энтони: так трюк с self является единственным вариантом здесь? можете ли вы подтвердить, что решение Мэтью не будет работать? – Pablo 1 May 2010 в 14:03
  • 4
    @Michael: Прежде всего, это не «трюк». это как раз то, как все работает в Javascript. Ответ Матфея, который сейчас стоит на момент написания этого комментария, не работает. Раньше была версия, которая могла бы сработать, но она включала передачу this в качестве параметра, который был ненужным и неудобным (любой вызывающий абонент retrieve_rate знал бы это ненужное специальное требование). – AnthonyWJones 1 May 2010 в 20:26
  • 5
    передача this в качестве аргумента (function(self){...})(this) в setInterval не работала для меня, потому что функция выполняется немедленно, а не задерживается. Решение @Joel Fillmore для меня работает – Homan 21 January 2013 в 20:59

Это не решение для красоты, но оно широко используется:

var self = this;
var ajax = null;
//...
ajax.onload = function() {
    self.prefs....;
}
-1
ответ дан Crozin 29 August 2018 в 00:19
поделиться
  • 1
    Проблема в том, как setInterval вызывает функцию retrieve_rate, значение this внутри метода относится к глобальному объекту ... – CMS 1 May 2010 в 09:15

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

это законно в javascript и сохраняет много кода:)

7
ответ дан Daniel Apostolov 29 August 2018 в 00:19
поделиться

Это было бы самое чистое решение, так как большую часть времени вы действительно хотите переключить этот контекст для своих последовательных вызовов методов:

Также легче понять концепцию.

    // 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);
1
ответ дан Dbl 29 August 2018 в 00:19
поделиться

Поведение setInterval по умолчанию - это привязка к глобальному контексту. Вы можете вызвать функцию-член, сохранив копию текущего контекста. Внутри retrieve_rate переменная this будет правильно привязана к исходному контексту. Вот как выглядит ваш код:

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

Бонусный совет: для простой ссылки на функцию (в отличие от ссылки на объект, которая имеет функцию-член) вы можете изменить контекст с помощью JavaScript call или apply.

18
ответ дан Joel Fillmore 29 August 2018 в 00:19
поделиться
  • 1
    Это сработало для меня, однако призыв к вызову не нужен. Контекст retrieve_rate должен быть установлен по умолчанию, потому что он вызывается как функция-член. – Dreendle 7 February 2012 в 14:47
  • 2
    @Dreendle - вы правы, я вспомнил, что решил это для ссылки на функцию обратного вызова, где это было необходимо. Я исправил ответ, спасибо! – Joel Fillmore 8 February 2012 в 18:43
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
        }
    }
0
ответ дан Matthew Flaschen 29 August 2018 в 00:19
поделиться
  • 1
    this внутри функции, переданной в setInterval, будет ссылаться на глобальный объект. Вы имели в виду context.retrieve_rate вместо this.retrieve_rate? – CMS 1 May 2010 в 09:11
  • 2
    Спасибо, что заметили это, CMS. – Matthew Flaschen 1 May 2010 в 09:13
  • 3
    Это эволюционировало в правильном направлении, не нужно, чтобы контекст передавался как параметр. – AnthonyWJones 1 May 2010 в 09:16
  • 4
    @Matthew, Anthony Итак, как мне получить доступ к нему из onload? Пробовал this.prefs, но не работал ... – Pablo 1 May 2010 в 09:19
  • 5
    Приветствую вас, Мэтью, кстати, вам не нужно использовать call, context.retrieve_rate() достаточно, так как у вас есть базовый объект (context.) – CMS 1 May 2010 в 09:19
this.intervalID = setInterval(this.retrieve_rate.bind(this), this.INTERVAL);
69
ответ дан Nechehin 29 August 2018 в 00:19
поделиться
  • 1
    Это правильное решение. Для принятого решения требуется излишне большее количество кода. – theoutlander 23 May 2014 в 00:37
  • 2
    Но этот метод имеет недостаток. Скорее всего, он не будет работать со старыми версиями IE – Nechehin 11 June 2014 в 13:25
  • 3
    @Nechehin Стоит отметить. Но это еще более чистое решение. – connorbode 11 March 2015 в 01:10
  • 4
    Это поддерживается, так как IE9 - это чистое решение для меня. – barbara.post 20 April 2015 в 08:37
  • 5
    Если вам нужна поддержка IE8 и , вы используете Underscore.js , вы можете использовать _.bind : this.intervalID = setInterval(_.bind(this.retrieve_rate, this), this.INTERVAL); – gfullam 21 August 2015 в 15:44

При улучшенной поддержке браузера время теперь полезно использовать расширение EcmaScript 6, метод стрелки => , чтобы сохранить this правильно.

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

Использование метода => сохраняет this, когда retrieve_rate() вызывается интервалом. Нет необходимости в напуганном себе или прохождении this в параметрах

8
ответ дан Pete 29 August 2018 в 00:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: