Javascript - 暂停执行,直到flag变为true

时间:2012-12-17 21:41:09

标签: javascript jquery synchronization sync wait

如何暂停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时,ready var变为true:

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

但是当执行时我会发现这个错误:

 Maximum call stack size exceeded error

任何想法? 谢谢!

5 个答案:

答案 0 :(得分: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);
  }
} 

答案 1 :(得分:0)

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

答案 2 :(得分: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;
})

P.S。http://api.jquery.com/category/deferred-object/

答案 3 :(得分:0)

您确定在iframe加载函数中设置为true的ready变量与在调用另一个settimeout之前检查的变量相同。似乎iframe加载函数中的一个是局部变量而另一个是全局变量。

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

答案 4 :(得分:-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()