Javascript 如何在回调期间从此事件侦听器中删除事件侦听器
我有一个页面,上面有一些javascript,用于收听一系列音频文件中的一些故事。我使用爆米花库为特定的时间戳添加脚注,当音频播放时,这些时间戳会在页面上突出显示文本中的单词。我有一个javascript对象AudioPlayer(本例中的实例称为ap),它包含许多音频元素和许多爆米花实例。当音频元素第一次“loadedmetadata”时,如果我有该项的时间戳,我想创建爆米花脚注。但是,我不想对给定的音频项多次运行此函数。也就是说,人们可以单击某个项目并重新加载它,但我不想重新创建时间戳。因此,我编写了如下回调代码,以便在获取给定项的时间戳时运行:Javascript 如何在回调期间从此事件侦听器中删除事件侦听器,javascript,audio,popcornjs,Javascript,Audio,Popcornjs,我有一个页面,上面有一些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();
}
//尝试加载此文件的任何时间戳
this.loadTS=函数(ann){
var xhr=new XMLHttpRequest();
xhr.open(“GET”),window.location.protocol+“/”+
window.location.hostname+“/sitename/timestaps/”+
window.location.pathname.substring(
window.location.pathname.lastIndexOf(“/”)+1)+“.json”,
正确的);
xhr.onreadystatechange=函数(){
如果(xhr.readyState==4&&xhr.status==200){
console.log(xhr.responseText);
this.timestaps=JSON.parse(xhr.responseText);
for(此.timestamps中的var idx){
var stampX=函数(){
//这是一个音频元素,获取它的索引
//盖章
var x=window.ap.audios.indexOf(本);
//需要删除此listner,这样它就不会再次启动!
这个.removeEventListener('loadedmetadata',stampX);//看起来每次都会重新创建stampX,因为您在onreadystatechange函数中声明了它
这意味着您使用的每个addEventListener都会获得不同的回调函数
您需要做的是分离它的逻辑,将它移到词法范围的更高位置,例如,在声明xhr对象的地方,甚至是在loadTS减速之外。这样,addEventListener和removeEventListener都将指向同一个函数。编辑:fistuks看到了上面的答案,我认为这是正确的JU在我写了下面的内容之后,我将留下这个,因为它在问题的上下文中举例说明了解决方案
我有一个可行的解决方案,但我仍然想知道更多的原因
对我来说,解决这个问题的方法是将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();
}
现在这个函数只调用了一次,爆米花也运行得很好。尽管如此,我还是很喜欢听到关于上面错误的评论