2011-04-17 105 views
1
//I have the following function: 
    function handle_message(msg) 
    { 
     //do work 
     console.log('some work: '+msg.val); 
     //call next message 
     msg.next(); 
    } 

//And array of message objects: 
var msgs = [ {val : 'first msg'}, { val : 'second msg'}, { val : 'third msg'}]; 

//I link messages by setting next parameter in a way that it calls handle_message for the next msg in the list. Last one displays alert message. 
msgs[2].next = function() {alert('done!')}; 
msgs[1].next = function() {handle_message(msgs[2]);}; 
msgs[0].next = function() {handle_message(msgs[1]);}; 

//Start the message handle "chain". It works! 
handle_message(msgs[0]); 

//======== Now I do exactly the same thing but I link messages using the for loop: 

for (var i=msgs.length-1; i>=0; i--) 
{ 
    if (i==msgs.length-1) 
    { 
     msgs[i].next = function() {alert('done!');}; 
    } 
    else 
    { 
     msgs[i].next = function() {handle_message(msgs[i+1]);}; 
    } 
} 

//Start the message handling chain. It fails! It goes into infinite recursion (second message calls itself) 
handle_message(msgs[0]); 

能夠解釋它爲什麼會發生?或者,也許這種模式的替代?我的情況是這樣的:我收到一個包含消息的數組,我必須按順序處理它們,另一個同步地處理它們。問題是一些消息需要發射一系列動畫(jqwuery animate(),這是異步的),並且在最後一個動畫完成之前無法處理以下消息。由於JavaScript中沒有sleep(),我試圖在消息完成後調用下一個消息的情況下使用這種模式(在動畫的情況下,我只是將'next'函數指針傳遞給動畫的「complete」回調函數)。無論如何,我想動態構建這個「鏈」,但發現了這個奇怪的(?)行爲。閉環中的javascript關閉

+0

你應該真的在爲這個類使用類,用原型對象。 – RobertPitt 2011-04-17 19:49:55

+2

這是一個非常糟糕的問題標題。今後,請嘗試總結一下您看到的讓您感到困惑的結果,或者您嘗試實現的結果。你不妨發佈一個題爲「我很困惑」或「幫助!」的問題。 – Phrogz 2011-04-17 19:56:40

+0

你說得對,我改變了它。 – PawelRoman 2011-04-17 20:05:01

回答

3

你需要一個封閉使它的工作:

function handle_message(msg) { 
    console.log('some work: ' + msg.val); 
    msg.next(); 
} 

var msgs = [{val :'first msg'},{val:'second msg'},{val:'third msg'}]; 

for (var i = msgs.length - 1; i >= 0; i--) { 
    (function(i) { 
     if (i == msgs.length - 1) { 
      msgs[i].next = function() { alert('done!'); }; 
     } else { 
      msgs[i].next = function() { handle_message(msgs[i + 1]); }; 
     } 
    })(i); 
} 

handle_message(msgs[0]); 

現場演示:http://jsfiddle.net/simevidas/3CDdn/

說明:

問題是與該函數表達式:

function() { handle_message(msgs[i + 1]); } 

這個函數有一個活參考i變量。當調用此函數時,for循環長時間結束,i的值爲-1。如果要捕獲當前值i(迭代期間的值),則需要額外的包裝函數。該函數永久地捕獲當前值i(作爲參數)。

+0

......或者你可以在需要的地方使用後一個函數的閉包。 – Phrogz 2011-04-17 19:55:48

+0

@Progro你是指在其他分支? – 2011-04-17 20:00:45

+1

@ŠimeVidas是;你的回答同樣有效,只是評論OP。另外請注意,當循環結束時不是'0'時,該值實際上是'-1'。 – Phrogz 2011-04-17 20:02:39

1

想想你在閉包中捕獲的值。

msgs[i].next = function() {handle_message(msgs[i+1]);}; 

這抓住了i價值,而是讓你得到一個無限循環它改變了下一次迭代。

在循環結束我是-1因此i+1將會一遍又一遍的相同的消息。

2

我認爲這個問題是i沒有價值,你覺得它有:

// i is defined here: 
for (var i=msgs.length-1; i>=0; i--) 
{ 
    if (i==msgs.length-1) 
    { 
     msgs[i].next = function() {alert('done!');}; 
    } 
    else 
    { 
     msgs[i].next = function() { 
      // when this line gets executed, the outer loop is long finished 
      // thus i equals -1 
      handle_message(msgs[i+1]); 
     }; 
    } 
} 

看點#5瓶蓋在循環http://blog.tuenti.com/dev/top-13-javascript-mistakes/

+0

感謝您的鏈接! – PawelRoman 2011-04-17 20:05:51