2016-10-03 12 views
0

一連のオーディオファイルに含まれるいくつかのストーリーを聞くためのJavaScriptが付いたページがあります。私はポップコーンライブラリを使用して、脚注を特定のタイムスタンプに追加し、音声が再生されるときにページ上のテキスト内の単語をハイライト表示します。私は多くのオーディオ要素と多くのポップコーンのインスタンスを含むjavascriptオブジェクトAudioPlayer(この例ではインスタンスはpと呼ばれます)を持っています。最初にオーディオ要素に '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(); 
} 

しかし、私はaudio要素が再ロードされます場合は、「stampX」は、より再び呼び出さなっていることを、このコードをテストで見つかった:私は与えられたアイテムのタイムスタンプを取得するときにそのため、私は実行するには、このようにコールバックコードを書きましたので、私の唯一の結論は、removeEventListenerが何らかの形で、以下のaddEventListenerと同じ参照を取得していないということです。

私はこれをデバッグするのが難しいと思っています。私は、イベントリスナー(関数呼び出しではない)の関数参照が必要なので、変数をstampXに渡すことはできません。

とにかく、これを書くための適切な方法を見つけるのが難しいです。私は、最初にstampXが呼び出されたときにeventListenerを削除できるようにしています。

答えて

1

これは、onreadystatechange関数内で宣言するため、いつもstampXが再作成されるようです。

これは、あなたが行うすべてのaddEventListenerが異なるコールバック関数を取得することを意味します。

xhrオブジェクトを宣言している場所、またはloadTS減速の外にあるexplplの場合は、ロジックを分離して、それを外側に移動し、字句範囲を上に移動する必要があります。このようにして、addEventListenerとremoveEventListenerの両方が同じ関数を指し示します。

0

EDIT:私が以下に書いた直後に正しいと受け入れたfistuksで上記の答えを見た。私はこれを残しておきます。なぜなら、問題の文脈で解決策を例示しているからです。


私はうまくいく解決策を持っていますが、私はまだそれ以上の理由を知りたいです。

私の問題は、xhr.onreaystatechangeのコールバックの外側で、stampXを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();  
    } 

この機能は一度しか呼び出されず、ポップコーンはうまく機能しています。しかし、何が間違っているのかについてのコメントを聞くのが大好きです。

関連する問題