如何链接ajax请求?

IT技术 javascript jquery asynchronous
2021-02-21 05:09:38

我必须与迫使我链接请求的远程 api 进行交互。这是异步模式下的回调地狱:

// pseudocode: ajax(request_object, callback)
ajax(a, function() {
  ajax(b(a.somedata), function() {
    ajax(c(b.somedata), function() {
      c.finish()
    }
  }) 
})

在同步模式下它会更具可读性:

sjax(a)
sjax(b(a.somedata))
sjax(c(b.somedata))
c.finish()

但是Sjax是邪恶的:)我该怎么做,在一个漂亮的不那么邪恶和可读的方式?

6个回答

你可以有一个函数,它传递一个整数来说明请求所在的步骤,然后使用 switch 语句来确定下一步需要发出什么请求:

function ajaxQueue(step) {
  switch(step) {
    case 0: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { ajaxQueue(1); } 
    }); break;
    case 1: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { ajaxQueue(2); }
            }); break;
    case 2: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { alert('Done!'); }
            }); break;
  }
}

ajaxQueue(0);

希望有帮助!

ASP.NET 3.5 的 WebServices 就是这样设置的。JS 端的所有 WebMethods 都有一个默认的回调函数(好吧,如果你这样设置的话),你可以打开服务器上调用的方法名称来决定如何处理响应。在这个例子中我可能会改变的一件事是不传递数字,而是使用更多类似枚举的方法:ajaxQueue(some_name); 所以你知道你的函数调用在做什么。
2021-05-03 05:09:38
哦该死的抱歉,最近编写了很多 PHP 程序,而我的 JavaScript 生rust了。以正确的语法发布更新:)
2021-05-08 05:09:38
您不能以这种方式为参数提供默认值。但我喜欢这个解决方案。
2021-05-16 05:09:38

不要使用匿名函数。给他们起名字。我不知道你是否能够做到我在下面写的:

var step_3 = function() {
    c.finish();
};

var step_2 = function(c, b) {
    ajax(c(b.somedata), step_3);
};

var step_1 = function(b, a) {
  ajax(b(a.somedata), step_2);
};

ajax(a, step_1);

如果回调始终返回下一个请求所需的参数,则此函数应将 ajax 请求列表链接在一起:

function chainajax(params, callbacks) {
  var cb = shift(callbacks);
  params.complete = function() {
    var newparams = cb(arguments);
    if (callbacks)
      chainajax(newparams, callbacks);
  };
  $.ajax(params);
};

您可以单独定义这些回调函数,然后将它们链接在一起:

function a(data) {
  ...
  return {type: "GET", url: "/step2.php?foo"}
};
// ...
function d(data) { alert("done!"); };

chainajax({type: "GET", url: "/step1.php"},
  [a, b, c, d]);

您还可以在对 chainajax 的调用中将函数声明为“内联”,但这可能会让人有点困惑。

也许您可以做的是编写一个服务器端包装函数。这样您的 javascript 只对您自己的 Web 服务器进行一次异步调用。然后您的 Web 服务器使用 curl(或 urllib 等)与远程 API 进行交互。

@PatrikAkerstrand,服务器上的 urllib - 比客户端上的嵌套回调更难阅读。=)
2021-05-09 05:09:38

更新:如果您使用 jQuery,我已经了解了一个更好的答案,请参阅标题下的更新:Using jQuery Deffered

旧答案:

您还可以使用Array.reduceRight(当它可用时)来包装$.ajax调用并将列表转换为:[resource1, resource2]$.ajax({url:resource1,success: function(...) { $ajax({url: resource2...(我从 Haskell 中学到的一个技巧,它是 fold/foldRight 函数)。

下面是一个例子:

var withResources = function(resources, callback) {
    var responses = [];
    var chainedAjaxCalls = resources.reduceRight(function(previousValue, currentValue, index, array) {
        return function() {
            $.ajax({url: currentValue, success: function(data) {
                responses.push(data);
                previousValue();
            }})
        }
    }, function() { callback.apply(null, responses); });
    chainedAjaxCalls();
};

然后你可以使用:

withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
    // called only if the ajax call is successful with resource1 and resource2
});

使用 jQuery 延迟

如果您使用的是 jQuery,则可以通过使用以下函数来利用jQuery DefferedjQuery.when()

 jQuery.when($.get('/api/one'), $.get('/api/two'))
       .done(function(result1, result2) { 
              /* one and two is done */
        });
这是一个很好的、易于理解的JQuery 解释 - medium.com/coding-design/writing-better-ajax-8ee4a7fb95f - 请注意如何将 $.ajax() 调用分配给变量的部分,然后调用.done() 方法,作为避免缩进的快速方法。
2021-04-20 05:09:38