等待从 javascript 函数返回,直到满足条件

Posted

技术标签:

【中文标题】等待从 javascript 函数返回,直到满足条件【英文标题】:Wait to return from a javascript function until condition met 【发布时间】:2012-01-10 07:02:06 【问题描述】:

这是一个奇怪的问题。我有一个使用 Crockford 式公共/私有成员构建的客户端对象:

var client = function() 
  var that, remote_data, other_data; 

  // add public interface
  that.doStuff = function()...

  // wait for remote resources to load
  remote_data = jsonRequest1();
  other_data  = jsonRequest2();

  return that;
;

我遇到的问题是,我需要在返回新的“那个”对象(表示客户端就绪)之前加载一些远程 JSON 资源。数据是异步返回的(显然),我正在设置布尔变量来指示每个远程资源何时返回。

我想过做如下的事情:

return whenInitialized(function()  return that; );

whenInitialized 函数返回两个布尔标志是否为真。我会将它与 setInterval 结合使用,但我确信这不会起作用。

非常感谢您的建议。

【问题讨论】:

【参考方案1】:

为了在异步操作成功后运行代码,您需要一个延续。它可以只是您的代码在操作完成时调用的回调。

类似这样的:

var client = function(done)  // done is the callback
  var that, remote_data, other_data; 

  // add public interface
  that.doStuff = function()...

  // wait for remote resources to load
  var done1 = false, done2 = false;
  var complete1 = function()  done1 = true; if (done2) done(); ;
  var complete2 = function()  done2 = true; if (done1) done(); ;
  remote_data = jsonRequest1(complete1);
  other_data  = jsonRequest2(complete2);

  return that;
;

但是这些控制标志真的很烦人,而且不能真正扩展。一个更好的声明方式是使用类似jQuery deferreds:

$.when(jsonRequest1(), jsonRequest2()).then(done);

【讨论】:

+1 用于 jQuery 延迟。我才刚刚开始掌握它们的窍门,它们会做出如此美妙的事情。 谢谢乔丹。我理解按照您的建议使用回调模式,在数据全部加载后调用“完成”回调。示例用法: var my_client = client(function() alert('done!'); );但是,在等待回调时, my_client 变量将可用,处于无效状态。你会如何调和这个?我想一种解决方案是更改客户端界面,因此不需要返回客户端。 @Chris Johnson:是的,您可以将该客户端提供给回调:done(that),并且不要从 client 函数返回任何内容。那么你的客户端代码就像:client(function(my_client) ... );.【参考方案2】:

您可以执行一个循环(可以选择超时)来等待异步完成。警告,这将(按要求)阻止所有其他功能,如果花费时间过长,可能会导致浏览器冻结。但是,您确实应该找出一种异步方式来做您需要的事情,而不是像这样阻塞。

var syncRequest = function(options) 
    var is_finished = false;
    var result;
    var finished_callback = function(response) 
        is_finished = true;
        result = response.result;
    

    ajax_request(options, finished_callback);

    // timeout in 30 seconds
    var timeout = (new Date()).getTime() + 30000;
    while ( !is_finished ) 
        if ( (new Date()).getTime() >= timeout ) 
            alert('Request timed out');
        

        // do nothing, just block and wait for the request to finish
    

    return result;

【讨论】:

我之前做过类似的实验,但我的浏览器总是冻结。由于大多数浏览器只在一个线程中执行 javascript,因此使用轮询不是一个好主意(因为 JavaScript 没有 sleep() 或类似的东西)。 确实如此。这是一个糟糕的解决方案,但对于 OP 的要求来说是一个有效的解决方案。最好找出一种异步方式来做这件事,我相信如果你想得够多,所有问题都有一个异步解决方案。 如果您要使用阻塞解决方案,为什么不首先执行同步 ajax 请求? OP 要求提供阻塞解决方案。如果您正在执行 JSONP,则无法执行同步请求。

以上是关于等待从 javascript 函数返回,直到满足条件的主要内容,如果未能解决你的问题,请参考以下文章

Javascript:永远不会从等待返回

等待函数完成,直到回调到来

等待队列-30

Rxjs 可观察等待,直到满足某些条件

等待模态显示时进度条的最佳实践

Python Selenium,被动等待,直到满足某些页面条件,然后接管[重复]