簡體   English   中英

如何在回調期間從此事件監聽器中刪除

[英]how to remove event listener from this during callback

我有一個帶有一些javascript的頁面,用於收聽一系列音頻文件中的一些故事。 我使用爆米花庫向特定的時間戳添加腳注,從而在音頻播放時突出顯示頁面上文本中的單詞。 我有一個JavaScript對象AudioPlayer(此示例中的實例稱為ap),其中也包含許多音頻元素和許多爆米花實例。 音頻元素第一次具有“ loadedmetadata”,如果我有該項目的時間戳,我想創建爆米花腳注。 但是,對於一個給定的音頻項目,我不想多次運行此功能。 也就是說,人們可以單擊某個項目並重新加載它,但是我不想重新創建時間戳記。 因此,我編寫了這樣的回調代碼,以便在獲得給定項目的時間戳時運行:

// 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相同的引用。

我發現這很難調試。 我無法將變量傳遞給stampX,因為需要事件偵聽器的函數引用(而不是函數調用)。

無論如何,我很難找到正確的編寫方式,以便在第一次調用stampX時可以刪除eventListener。

好像每次都重新創建了stampX,因為您在onreadystatechange函數中聲明了它。

這意味着您執行的每個addEventListener都會獲得一個不同的回調函數。

您需要做的是分離其邏輯,將其移到詞法范圍之外,例如在聲明xhr對象或什至不在loadTS減速度范圍內。 這樣,addEventListener和removeEventListener都將指向同一函數。

編輯:我在下面寫完之后,看到了fistuks給出的答案,我認為是正確的。 我將保留這一點,因為它在問題的上下文中舉例說明了解決方案。


我有一個可行的解決方案,但我仍然很想知道為什么。

對我而言,解決此問題的方法是將stampX移到xhr.onreaystatechange回調之外的window.ap對象名稱空間。

  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();      
  }

現在該函數僅調用一次,爆米花運行良好。 不過,我仍然喜歡聽到關於上面有什么問題的評論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM