如何在JavaScript中实现同步包装器?

时间:2012-10-08 04:36:18

标签: javascript jquery

我在Javascript中使用Googles Analytics API。

它们提供了一个获取列表结果的方法,一旦执行完毕,它就会调用带有结果的回调方法。

看起来像这样:

gapi.client.analytics.management.accounts.list().execute(handleAccounts);

...

function handleAccounts(results) {
        if (!results.code) {
        if (results && results.items && results.items.length) {

// See this code below.

        } else {
            console.log('No accounts found for this user.')
        }
    } else {
        console.log('There was an error querying accounts: ' + results.message);
    }
}

一般来说这太棒了,但是......我需要一个所有子项目的扁平列表,所以我一直这样打电话:

 $.each(results.items, function (index, value) {

gapi.client.analytics.management.webproperties.list({ 'accountId': value.Id}).execute(handleWebproperties);
// and so on..
            })

问题在于,如果在任何级别你有多个项目,你最终会有多个异步调用射击,我不知道他们什么时候完成了最终列表。

除了写一些内容以跟踪已经拨打了多少电话,然后等待该总数回来。

我怎样才能轻易知道它们何时完成?

感谢。

总结:

用户可以拥有多个帐户,帐户可以拥有多个属性,属性可以包含多个配置文件。

我需要用户所有帐户的所有个人资料。

3 个答案:

答案 0 :(得分:0)

解决这个问题的方法是跟踪你已经(或将要制作)的异步调用次数,并在每个响应中收到计数的减量并检查最后一个是否已完成。重要的是确保您有一个强大的错误处理,以防一个响应生成错误并且未成功完成。

你似乎知道这是一个选项,目前还不清楚你为什么不追求这个,但这是解决这个问题的方法。也可以使用jQuery deferreds来跟踪最后一个完成的时间,但是这只是使用一个库来为你计算 - 它在下面仍然基本相同。

答案 1 :(得分:0)

基于我之前写的fork函数:[{3}}。我会这样做:

var queryFunctions = []
$.each(results.items, function (index, value) {
    queryFunctions.push(function(callback){
        gapi.client.analytics.management.
            webproperties.list({ 'accountId': value.Id}).
            execute(callback);
    });
})

fork(queryFunctions,function(result){
    // This is the final callback, so do processing here
})

fork的实施就是这样:

function fork (async_calls, shared_callback) {
  var counter = async_calls.length;
  var all_results = [];
  function makeCallback (index) {
    return function () {
      counter --;
      var results = [];
      // we use the arguments object here because some callbacks 
      // in Node pass in multiple arguments as result.
      for (var i=0;i<arguments.length;i++) {
        results.push(arguments[i]);
      }
      all_results[index] = results;
      if (counter == 0) {
        shared_callback(all_results);
      }
    }
  }

  for (var i=0;i<async_calls.length;i++) {
    async_calls[i](makeCallback(i));
  }
}

正如您所看到的,它所做的就是跟踪counter变量中的调用次数。但它全部封装在一个函数中,因此您可以重用逻辑。另外,我认为它使代码更加整洁。

答案 2 :(得分:0)

您可以使用jQuery Deferred功能执行此类操作。基本上,如果将回调包装在Deferred对象中,则使用$.when(...)将它们组合在一起。

这样的东西(对你来说最有意义的确切结构将取决于你如何使用它,这段代码假设你需要在每次回调中做一些特定的事情,并知道它们什么时候完成):

var promises = [];
$.each(results.items, function (index, value) {
    var deferred = new $.Deferred();
    gapi.client.analytics.management.webproperties.list({ 'accountId': value.Id}).execute(function(results) {
        handleWebproperties(results);
        deferred.resolve();
    });
    promises.push(deferred.promise());
    // and so on...
});

$.when.apply(this, promises).done(function() {
    alert("Everything is finished!");
});

注意我只是直接编码到浏览器窗口,所以这可能不是100%正常运行。 :)