2016-10-03 6 views
0

У меня есть страница с некоторым javascript для прослушивания некоторых рассказов, которые находятся в серии аудиофайлов. Я использую библиотеку попкорна для добавления примечаний к конкретным временным меткам, которые выделяют слова в тексте на странице при воспроизведении звука. У меня есть объект javascript AudioPlayer (экземпляр в этом примере называется ap), который содержит много аудио-элементов и множество экземпляров попкорна. В первый раз, когда аудио-элемент имеет «загруженные метаданные», если у меня есть метки времени для этого элемента, я хочу создать сноски попкорна. Но я не хочу запускать эту функцию более одного раза для данного аудио-элемента. То есть люди могут нажать на элемент и перезагрузить его, но я не хочу воссоздавать временные метки. По этой причине, я написал обратного вызова код, как это работать, когда я получаю временные метки для данного элемента:как удалить прослушиватель событий из этого во время обратного вызова

// try to load any timestamps for this file 
this.loadTS = function(ann) { 
    var xhr = new XMLHttpRequest(); 
    xhr.open("GET", window.location.protocol+"//"+ 
        window.location.hostname+"/sitename/timestamps/"+ 
        window.location.pathname.substring(
        window.location.pathname.lastIndexOf('/')+1)+".json", 
      true); 
    xhr.onreadystatechange=function(){ 
    if(xhr.readyState==4 && xhr.status==200){ 
     console.log(xhr.responseText); 
     this.timestamps = JSON.parse(xhr.responseText); 
     for(var idx in this.timestamps){ 

     var stampX = function(){ 
      // this is an audio element, get it's index to 
      // do the stamping 
      var x = window.ap.audios.indexOf(this); 

      // need to remove this listner so it doesn't fire again!   
      this.removeEventListener('loadedmetadata',stampX); // <- fail :(
      // window.ap.audios[x] 
      // .removeEventListener('loadedmetadata',stampX); 
      // ^^ this failed too :(:(

      // stamp away! 
      window.ap.stampItem(window.ap.winIGTs[x], 
      window.ap.timestamps[x], window.ap.audios[x], 
       window.ap.popcorns[x]); 

     }; 

     this.audios[idx].addEventListener('loadedmetadata', stampX); 

     if(ann) 
      this.textIGTs[idx].setAttribute("class","igt existstamps"); 
     } 
    } else console.log(xhr.status); 
    }.bind(this); 
    xhr.send(); 
} 

Но я нашел в тестировании этого кода, «stampX» становится вызван более раз, если аудио элемент получает перезагружается , поэтому мой единственный вывод заключается в том, что removeEventListener каким-то образом не получает ту же ссылку, что и addEventListener.

Я нахожу это трудным для отладки. Я не могу передать переменную в штампX, потому что вам нужна ссылка на функцию для прослушивателя событий (а не вызов функции).

Во всяком случае, мне трудно найти правильный способ написать это, чтобы я мог удалить eventListener при первом вызове штампаX.

ответ

1

Похоже, что stampX воссоздается каждый раз, потому что вы объявляете его внутри функции onreadystatechange.

Это означает, что каждый addEventListener вы получаете другую функцию обратного вызова.

Что вам нужно сделать, это отделить его логику, вывести ее снаружи, выше в лексическом пространстве, например, где вы объявляете объект xhr или даже вне торможения loadTS. Таким образом, как addEventListener, так и removeEventListener будут указывать на одну и ту же функцию.

0

EDIT: увидел ответ выше, фистуки, которые я принял как правильно сразу после того, как я написал ниже. Я оставлю это, потому что это иллюстрирует решение в контексте вопроса.


У меня есть решение, которое работает, но я все равно хотел бы узнать больше о том, почему.

Для меня проблема заключалась в перемещении stampX в пространство имен объектов window.ap, вне обратного вызова для xhr.onreaystatechange.

this.stampX = function(e) { 
    // this is an audio element, get it's index to do the stamping 
    var x = window.ap.audios.indexOf(e.target); 
    // need to remove this listner so it doesn't fire again! 
    this.audios[x].removeEventListener('loadedmetadata',this.stampX); 

    this.stampItem(this.winIGTs[x], this.timestamps[x], this.audios[x], 
     this.popcorns[x]); 

    }.bind(this); 

    // try to load any timestamps for this file 
    this.loadTS = function(ann) {  
    var xhr = new XMLHttpRequest(); 
    xhr.open("GET", window.location.protocol+"//"+ 
        window.location.hostname+"/sitename/timestamps/"+  
        window.location.pathname.substring(
        window.location.pathname.lastIndexOf('/')+1)+".json",  
       true); 
    xhr.onreadystatechange=function(){ 
     if(xhr.readyState==4 && xhr.status==200){ 
     console.log(xhr.responseText); 
     this.timestamps = JSON.parse(xhr.responseText); 
     for(var idx in this.timestamps){  
      this.audios[idx].addEventListener('loadedmetadata', this.stampX); 
      if(ann)  
      this.textIGTs[idx].setAttribute("class","igt existstamps");  
     } 
     } else console.log(xhr.status); 
    }.bind(this); 
    xhr.send();  
    } 

Теперь функция вызывается только один раз, и попкорны работают красиво. Тем не менее, я люблю слышать комментарии о том, что было неправильно выше.

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

  • Нет связанных вопросов^_^