2015-01-30 6 views
-2

Как я могу достичь ссылки на родительский «это» изнутри асинхронной функции обратного вызова, как в приведенном ниже фрагменте?Доступ к «this» в асинхронной функции обратного вызова в JavaScript

var imaginaryAjaxCall = function (fn) { 
    setInterval(fn, 1000); 
} 

function parent() { 
    this.foobar = "foo"; 

    imaginaryAjaxCall(function() { 
     this.foobar = "bar"; 
    }); 
} 

Вот jsfiddle для тестирования: http://jsfiddle.net/r0ueon53/11/

Edit: Я бросился на вопрос, и испортил его. Извините за то, что некоторые комментарии не имеют отношения к этому редактированию.

+1

Не знаете, где «это» используется, поскольку оно не находится в коде, но узнайте о ['bind()'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) – epascarello

+0

'setInterval (fn, 0)' ждет завершения основного скрипта перед запуском 'fn', даже если время установлено на ноль. – JJJ

+0

@epascarello 'this' здесь не проблема. Он правильно кэшируется с помощью 'this = this'. – JJJ

ответ

2

Javascript работает на одной ветке. Когда вы устанавливаете fn для выполнения с интервалом, вы получаете доступ к DOM Api, который действует асинхронным образом (даже если он не является асинхронным). Что происходит, DOM api будет вставлять обратный вызов в очередь обратного вызова каждый раз, когда interval является прошло. Итак, каждые 0 мс (ну, это на самом деле ближе к 4 мс, но это еще одна тема) fn будет вставлен в очередь обратного вызова.

Теперь обратные вызовы в очереди обратного вызова только получить побежал, когда CallStack пуст, поэтому, обратный вызов не получает просуществовала до после

document.getElementById('out').innerHTML = this.foobar; 

побежал, поэтому он выдает «Foo» вместо «бар».

http://jsfiddle.net/r0ueon53/13/

Если отложить эту линию на секунду, вы увидите, что выход «бар» вместо этого.

setTimeout(function() { 
    document.getElementById('out').innerHTML = that.foobar; 
}, 1000); 

http://jsfiddle.net/r0ueon53/12/

это работает, потому что setTimeout вставит его обратный вызов в очередь обратного вызова 1 вторых позже, таким образом, после setInterval обратного вызова, который изменил значение «бар».


Очевидно, что при работе с AJAX, используя SetTimeout, чтобы исправить это не будет соответствовать из-за различий в скорости сети. Вместо этого вы должны просто переместить .innerHTML в обратный вызов, который вы передали на вызов ajax.

Смежные вопросы