2011-04-17 106 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