2012-12-17 55 views
0

如何暂停JavaScript执行直到标志变为true?Javascript - 暂停执行,直到标志变为真

对于实施例中,我一个XML消息是这样的:

[...] 
<action> 
    <resource update>id</resourceupdate> 
</action> 
<action> 
    <event>id1</event> 
</action> 
<action> 
    <event>id2</event> 
</action> 
<action> 
    <event>id3</event> 
</action> 
[...] 

我希望事件节点只处理节点resourceupdate(这需要更多的时间来送达,后处理,因为它需要装载一个页的):

在JavaScript来处理具有一个迭代(每个此消息)我试着:

$(_response).find('ACTION').each(function() {  
if (tagName=="RESOURCEUPDATE") { 
    ready = false; 
    //load the resource with selected id in an iframe 
} else if (tagName=="EVENT") { 
    browserLoaded(); //the waiting function 
    eventhandler(); //consume the event 
} 
}); 

等待功能是:

function browserLoaded() { 
if (!ready) { 
    setTimeout(browserLoaded(),1000); 
} 
} 

,当iframe中加载准备var就成了真:

$(iframe).load(function() { 
    ready = true; 
}); 

,但执行的时候我会抓住这个错误:

Maximum call stack size exceeded error 

什么想法? 谢谢!

+2

'setTimeout(browserLoaded(),1000);'执行你的函数。你只是想引用你的功能;删除'()',以便它'setTimeout(browserLoaded,1000);' – Sampson

+0

感谢您的快速响应!好吧,没有更多的错误,但执行不会停止。 – jenjis

回答

0

这真是一个糟糕的主意,用某种标志。你必须使用延期模式。事情是这样的:

var resources = []; 
$(_response).find('ACTION').each(function() { 
    var deferred = resources.length > 0 ? resources[resources.length - 1] : null; 

    switch (tagName) { 
    case "RESOURCEUPDATE": 
     deferred = $.Deferred(); 

     //load the resource with selected id in an iframe 
     $(iframe).bind('load', function() { 
     deferred.resolve(/*specific arg1, arg2, arg3, ...*/) 
     }); 
     resources.push(deferred); 
     break; 
    case "EVENT":  
     if (deferred) { 
     deferred.done(function (/*specific arg1, arg2, arg3, ...*/) { 
      // process event node 
     }); 
     } 
     break; 
    } 
}); 

// clean up deferreds objects when all them will be processed 
$.when.apply($, resources).then(function() { 
    resources.length = 0; 
}) 

附:http://api.jquery.com/category/deferred-object/

+0

有趣,我会看看 – jenjis

+0

这是正确的答案;该代码不完全是我所需要的,但延期建议让我找到了解决问题的最佳解决方案。谢谢 – jenjis

0

的问题是在这个函数调用自身,直到堆栈已满:

function browserLoaded() { 
    if (!ready) { 
    //here you call browserLoaded function instead of passing a reference to the function 
    setTimeout(browserLoaded() ,1000); 
    } 
} 

你的功能应该是这样的:

function browserLoaded() { 
    if (!ready) { 
    // note the missing "()" 
    setTimeout(browserLoaded, 1000); 
    } 
} 
0

这是一个可怕的设计。你不需要'等待'超时机制。如果您通过jQuery ajax请求加载页面,请使用回调函数继续执行代码(您可以跟踪正在处理的“当前”项目并继续下一步)。如果您正在加载iFrames,那也是糟糕的设计,您应该转向jQuery ajax方式。

+0

我大大简化了代码,不包含不必要的信息。 实际上,iframe的加载函数包含几个处理程序,用于拦截用户交互将xml消息发送给servlet。 这将它们存储并将它们发送到其他客户端,这些客户端或多或少地通过上面表达的(简化)的通过异步回调函数的Get on语法来表示。 我无法处理iframe加载回调中的消息,因为这些是异步的,不一定会到达加载iframe – jenjis

+0

hmm,难道你至少不能使用iFrame的onLoad事件吗? –

+0

不是为了处理消息,而是至多要触发一个变量(就绪):( – jenjis

-1

你可以做的一件事就是设置一个轮询循环:使用setInterval检查每一次,如果变量已经设置并且clearInterval并且在其时间继续执行。

无论如何,它将成为一件痛苦的事情。从本质上讲,告诉Javascript运行后者的唯一方法是将其打包到函数中。当你这样做的时候,它会变得更容易,因为你可以传递这个函数,并在你完成后让异步代码回调它。

例如,您可能会处理这个样子:

//this is a simple "semaphore" pattern: 
var things_to_load_count = 1 
var check_if_done(){ 
    things_to_load_count--; 
    if(things_to_load_count <= 0){ 
     //code to do stuff after you finish loading 
    } 
}; 

$(_response).find('ACTION').each(function() { 
    if (tagName=="RESOURCEUPDATE") { 
     things_to_load_count++; 
     run_code_to_load_stuff(check_if_done) 
     //make sure that the run_code_to_load_stuff function 
     //calls the callback you passed it once its done. 
    } else if (tagName=="EVENT") { 
     //process one of the normal nodes 
    } 
}); 

//this will run the remaining code if we loaded everything 
//but will do nothing if we are still waiting. 
check_if_done() 
0

您确定在iframe加载函数中设置为true的就绪变量与在另一个settimeout被调用之前检查到的变量相同。看起来iframe加载函数中的一个是局部变量,另一个是全局变量。

或者两个就绪变量都是本地的。

+0

我在我的core.js的开头声明var ready = true(在任何分支或函数之外);之后我只做了任务,并且从未在别处声明变量。 – jenjis