2013-09-26 18 views
1

我會得到一點:我有這樣的循環:意外行爲倒閉:回調保持最後的值

for (var i = 1; i <= toSchedule; i++) { 
     when = trackWrapper.lastPlay + 
       (trackDuration + 
       (looper.timeInterval - trackDuration)); 

     track.play(true, when); 
     trackWrapper.lastPlay = when; 
    } 

play方法有這個身體內部:

[...] 
// Here when is a different value for each call (verified) 
// Many calls of the play method are performed before the returned function below is run as a callback 
     function playingCallback(myWhen){ 

      return function(buffers){ 
       // Here myWhen will always be equal to the value of the last call occurred BEFORE the first callback execution 
       console.log("myWhen = "+myWhen); 
       [...] 

      }; 
     }; 

     var realCallback = playingCallback(when); 

     track.scheduled.push(when); 
     track.recorder.getBuffer(realCallback); 

所以,例如:

play(true, 1); 
play(true, 2); 
play(true, 3); 

// Wait for it... 

myWhen = 3; 
myWhen = 3; 
myWhen = 3; 

現在:我讀過有關關閉,我讀過有關「臭名昭著的循環問題」,我心中已經e在StackOverflow上閱讀了數十個答案,但我無法弄清楚。這是我第二次遇到這種回調問題,因此在這一點上,我想我還沒有完全明白髮生了什麼。

請問您能解釋一下上面的代碼應該是錯誤的嗎?先謝謝你。

+0

你可以更清楚一點'play()'的定義嗎?顯示其參數被稱爲什麼等...... – nnnnnn

+0

您需要使用'play'參數,而不是來自循環的'when'變量。 – Bergi

+0

問題是......那不是控制玩家的方法。試圖用一堆預測的開始時間來控制它是註定要失敗的。例如,說用戶將音軌暫停10秒。問問你自己,以後的曲目的開始時間是否仍然有效?要形成一個曲目列表,你需要將TRACKS而不是時間推到一個棧上。然後你需要代碼爲玩家免費時提供服務。 –

回答

1

一般而言,您應該瞭解以下規則:即使在範圍退出後,clousure也可以訪問其「周圍範圍」。但是它將在執行時的狀態,而不是在關閉創建時的(!)

如果在循環內創建閉包,它將有權訪問循環變量。但循環很可能已經結束。所以循環變量將保存最後一個循環的值。

因此,如果您的閉包是回調函數,您應該在創建時創建相關範圍變量的副本,並在執行時使用此副本。你可以通過創建一個立即執行匿名函數的內部閉包來做到這一點(例如)

function myOuterScope(count) { 
    for(i=0; i<count; i++) { 
     setTimeout((function(local_i) { 
     // this function will be immediately executed. local_i is a copy of i at creation time 
     return function() { 
      // this is the function that will be called as a callback to setTimeout 
      // use local_i here, and it will be 0, 1, 2 instead of 3, 3, 3 
     } 
     })(i) 
     , 1000); 
    } 
} 
myOuterScope(3);