[英]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.