【问题标题】:Wait to return from a javascript function until condition met等待从 javascript 函数返回,直到满足条件
【发布时间】: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 结合使用,但我确信这不会起作用。

非常感谢您的建议。

【问题讨论】:

    标签: javascript asynchronous closures


    【解决方案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,则无法执行同步请求。
    猜你喜欢
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 2021-06-10
    • 2020-11-17
    • 2016-05-02
    相关资源
    最近更新 更多