摆脱javascript回调所需的嵌套

时间:2012-06-30 19:02:27

标签: javascript

我有一些javascript函数可以通过网络执行异步请求,并通过回调来“返回”数据。以下是我使用它时的示例:

RemoteQuery(server,query,function(ret) {
  // do something with ret
})

问题是,如果我连续多次查询,代码就会变得非常嵌套并且难以管理。由于我依赖于范围变量,我不能将这些函数中的每一个都拆分为单独的顶级函数。这是一个玩具示例:

RemoteQuery(server,query1,function(ret) {
      var x = ret[5]
      RemoteQuery(server,query2,function(ret) {
          var y = ret[3]
          if (x + y > 10) {
              RemoteQuery(server,query2,function(ret) {
                  // do more stuff
              })
          }      
      })
})

显然,如果我有超过2或3个查询它开始变得丑陋,我可能会有更多的东西!

理想情况下,我想在没有所有嵌套的情况下代表上述内容,例如

ret = RemoteQuery(server,query1)
var x = ret[5]
ret = RemoteQuery(server,query2)
var y = ret[3]
if (x + y > 10) {
    ret =RemoteQuery(server,query2)
    // do more stuff
}

但我唯一想到的可能是解析javascript,识别具有回调的函数,以正确的形式重写它们和eval,但这看起来非常复杂并且会使调试变得非常困难

有没有更好的机制来做到这一点?

3 个答案:

答案 0 :(得分:1)

执行此操作的“正确”方法是为它们编写函数声明,并避免依赖于作用域变量(因此将它们传递给每个函数)。类似的东西:

var myFunc1 = function(x, ret1) { 
  RemoteQuery(server, query, function(ret2) { 
    var y = ret[3];
    myFunc2(x, y, ret2);
  });
};

var myFunc2 = function(x, y, ret) { /* do more stuff */ };

RemoteQuery(server, query, function(ret1) {
  var x = ret[5];
  myFunc1(x, ret1);
});

由于您必须异步调用这些RemoteQuery,因此无法真正实现您在问题中建议的解决方案。使用Deferred对象可能会起到作用,但我认为你仍然需要重构你的函数(因为你的目标是避免嵌套)。

答案 1 :(得分:0)

如果您愿意使用JQuery以及Dojo的框架(我确信其他人也拥有它!)包含一个延迟对象,这将是一个不错的选择。

答案 2 :(得分:0)

一组链式函数怎么样?

function R1 (server, query, callback)
{
    RemoteQuery(server, query, function(ret) {
        // process ret
        if (x + y > 10)
          callback();
    }
}

function R2 (server, query, callback)
{    
    RemoteQuery(server, query, function(ret) {
        // process ret
        callback();
    }
}

function R3 (server, query, callback)
{
    RemoteQuery(server, query, function(ret) {
        // process ret
        callback();
    }
}

var functions = [R1, R2, R3]

function callAll(a, server, query)
{
    var callNext = function(callback, i)
    {
        if (i < a.length)
            a[i](server, query, function() { callback(callback, i + 1); });
    }
    callNext(callNext, 0);
}

callAll(functions, 'server', 'query');