Понимание обратного вызова javascript с помощью addEventListener

#javascript #callback #dom-events

#javascript #обратный вызов #dom-события

Вопрос:

У меня есть объектный литерал, возвращаемый функцией, и, в свою очередь, этот объект создает iframe и выполняет несколько действий, когда DOM загружается в этот iframe. Я хочу иметь возможность «получить» значение, возвращаемое обратным вызовом при запуске события. Вот упрощенный объект:

 var myFunc = function (url) {
  return {
      url: url,
      myMethod: function () {

          // some code here to create my iframe.

          var callbackFunc = function (event) {
             // do some stuff with the dom.
             return aValueAsynchronously;
          };

          var async = my_iframe.addEventListener("DOMContentLoaded", callbackFunc, true);
          my_iframe.src = this.url;
      }      
  }
}
  

После прочтения этого кода я использую его как следовать за ним:

 var myValue = myFunc.myMethod('http://www.example.org');
  

и когда example.org завершается загрузка в iFrame, DOMContentLoaded запускается обратный вызов, и возвращается значение (после некоторой логики). Как мне присвоить это значение myValue (строка выше)? Я понимаю, что для этого мне нужно использовать обратный вызов, но где и как?

Ответ №1:

Во-первых, приведенный вами код не может быть вызван myFunc.myMethod , поскольку значение функции не имеет myMethod свойства. Вместо этого функция возвращает объект с этим свойством. Итак, для начала вам нужно:

 var myValue = myFunc('http://foo.com').myMethod();
  

Однако это приведет только к вызову метода, который устанавливает обратный вызов. Чтобы на самом деле иметь доступ к aValueAsynchronously , вы могли бы создать замыкание вокруг этого значения:

 var myFunc = function(url){
  var aValueAsynchronously;
  return {
    val : aValueAsynchronously,
    myMethod: function(){
      var callback = function(evt){
        aValueAsynchronously = ...;
      };
      ...register your callback...
    }
  };
};

var obj = myFunc('http://foo.com');
obj.myMethod();
...some time passes, and eventually the callback occurs...
console.log( obj.val ); // This will be what was set in your callback
  

Однако вместо этого я бы лично написал код, чтобы я мог передать свой собственный обратный вызов для выполнения из обратного вызова iframe и просто передать специальное значение моему обратному вызову напрямую. (Это звучит запутанно; см. Код ниже.) Таким образом, вам не нужно ждать, пока значение станет доступным, а скорее вы получите уведомление, когда оно будет доступно:

 var myFunc = function(url,whenDone){
  return {
    myMethod: function(){
      var callback = function(evt){
        var aValueAsynchronously = ...;
        whenDone(aValueAsynchronously);
      };
      ...register your callback...
    }
  };
};

var myObj = myFunc('http://foo.com',function(specialValue){
  // use specialValue here
});
myObj.myMethod(); // Go
  

Комментарии:

1. Спасибо за ваш ответ! Я попробую два описанных вами решения и посмотрю, как это работает! 🙂

2. Мне нравится второе решение с прямой передачей значения обратного вызова! Это действительно демонстрирует силу JS! Еще раз спасибо!

Ответ №2:

Если myValue находится в области для обратного вызова, просто назначьте ему. Если он не входит в область видимости, то к нему необходимо обращаться как к свойству некоторого объекта, и ссылка на этот объект должна быть в области видимости для обратного вызова.

В простом случае, если myValue является глобальным, и вы ожидаете, что код будет выполняться в браузере, тогда обратный вызов может быть установлен window.myValue = ...; . В противном случае обратный вызов должен получить к нему доступ как к свойству глобального объекта (что эквивалентно window в браузере).

Итак, в вашей функции у вас может быть:

       var callbackFunc = function (event) {
         // do some stuff with the dom.

         window.myValue = aValueAsynchronously;

         return aValueAsynchronously;
      };
  

Или я полностью упустил суть?

Комментарии:

1. Спасибо, но я не запускаю это в браузере! Решение Phrogz сработало.

2. Затем вы можете получить ссылку на глобальный объект и использовать его вместо этого. Но да, я думаю, что Phrogz понял это.