如何使用jQuery等待来自回调的异步调用?

时间:2012-08-28 03:57:37

标签: javascript jquery ajax asynchronous

我正在使用基于select2 jQuery的替换组合框,我必须定义一个回调来处理从json rest Web服务收到的数据。

问题在于,在同一个回调中,我必须发出另一个GET请求来获取匹配记录的总数,以便select2可以决定是否必须加载更多结果(它具有无限滚动功能)< / p>

代码是这样的:

$("#country").select2({
  ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
    url: 'http://localhost:9000/api/countries',
    dataType: 'json',
    data: function(term, page) {
      return {
        filter: term,
        page: page,
        len: 10
      };
    },
    results: function(data, page) {
      return {
        results: data, more: ????
      };
    }
  }
});

问题是我不知道如何发出异步请求(我发出跨域请求,并且文档说在这种情况下不支持异步)并等待它完成后再返回表单结果回调。

select2页面的示例如下:

results: function (data, page) {
  var more = (page * 10) < data.total; // whether or not there are more results available
  // notice we return the value of more so Select2 knows if more results can be loaded
  return {results: data.movies, more: more};
}

问题是我的Web服务返回来自不同端点的记录总数,因此我必须再发出一个请求,如下所示:http:// localhost:9000 / api / countries?filter = term

任何想法?

3 个答案:

答案 0 :(得分:8)

你不能等待javascript中的异步回调。您必须重新构建代码,以根据实际回调的异步响应执行所有未来的工作。

如果你需要进行多个连续的ajax调用,那么你发出第一个ajax调用,在第一个ajax调用的成功处理程序或响应处理程序中,你发出第二个ajax调用,在第二个调用处理程序中,你发出执行你想做的任何数据。

如果您发现自己正在使用.select2()框架。在框架中,结果回调是ajax调用返回的位置。在那个函数中,您将使用普通的jQuery ajax调用发出第二个ajax调用,并且在第二个ajax调用的成功处理程序中,您将执行您尝试处理的最终数据。您将无法使用结果回调的正常返回值,因为在您需要返回时您将无法获得最终数据。我认为这仅仅是.select2()的限制,因为它只支持单个ajax调用。它只是意味着你不能使用一点内置行为并且必须自己使用你自己的代码来应用结果,但这并不意味着你必须抛弃.select2()来处理你所做的一切。使用它。

看起来您可能只想直接挂钩change事件而不使用其内置的ajax,因为如果您需要两个序列化的ajax调用,它看起来并不像它真的提供了很多。

答案 1 :(得分:4)

我研究了select2上的源代码,并最终提出了这个解决方案

var ajax = {
  url: 'http://localhost:9000/api/countries',
  len: 3,
};

$("#country").select2({
  query: function(options) {
    var data = {
      filter: options.term,
      page: options.page,
      len: ajax.len
    };
    $.ajax({
      url: ajax.url,
      data: data,
      dataType: 'json',
      type: 'GET',
      success: function(data) {
        $.ajax({
          url: ajax.url + '/count',
          data: { filter: options.term },
          dataype: 'json',
          success: function(resp) {
            var total = parseInt(resp, 10);
            var more = (options.page * ajax.len) < total;
            options.callback({results: data, more: more});
          }
        });
      }
    });
  },
});

正如您所看到的,当第一次获取(ajax.url)完成时,我发出另一个请求(ajax.url +'/ count')并且只有当第二个请求完成时我才调用options.callback,有效地序列化两个ajax调用...

实际上ajax function from select2具有更多功能,例如限制和丢弃无序响应,我只是移植了它们,但是我将它们排除在此响应之外,以免使示例复杂化。

答案 2 :(得分:0)

除了jfriend00的答案(这是优秀的,BTW)我发现了followgin解决方法,它基本上是同步发出请求,尽管jquery文档它似乎工作(至少使用chrome 18.0和jquery 1.8.0) )

我只是张贴它以防任何人发现它有用......

var config = {
  url: 'http://localhost:9000/api/countries',
  len: 20,
  term: ''
}
$("#country").select2({
  ajax: { 
    url: config.url,
    dataType: 'json',
    data: function(term, page) {
      config.term = term;
      return {
        filter: term,
        page: page,
        len: config.len
      };
    },
    results: function(data, page) { // parse the results into the format expected by Select2.
      var more = false;
      $.ajax({
        url: config.url + '/count',
        data: { filter: config.term },
        cache: false,
        async: false,
        success: function(resp) {
          var total = parseInt(resp, 10);
          more = (page * config.len) < total;
        },
        async:false
      });
      return {
        results: data, more: more
      };
    }
  }
});