【问题标题】:JavaScript promises with nested AJAX calls are not working带有嵌套 AJAX 调用的 JavaScript 承诺不起作用
【发布时间】:2016-08-12 07:05:26
【问题描述】:

在我的代码中,我有一个包含 3 个嵌套 AJAX 调用的函数,为了让它工作,我必须设置 Async=false

据我所知,Async=false 已弃用,我将 Async=false 替换为 promises

这是我编辑之前的函数:

self.getOrders = function (name) {
    var orders= [];
    var order= function (item, type1, type2) {
        var self = this;
        self.order= item;
        self.type1= type1;
        self.type2= type2;
    }

$.ajax({
    url: "/API/orders/" + name,
    type: "GET",
    async: false,
    success: function (orderResults) {
        var mappedOrders = $.map(orderResults, function (orderItem) {
        $.ajax({
            url: "/API/orders/property/" + orderItem.id + "/type1",
            type: "GET",
            async: false,
            success: function (property1Results) {
                 $.ajax({
                     url: "/API/orders/property/" + orderItem.id + "/type2",
                     type: "GET",
                     async: false,
                     success: function (property2Results) {
                          orders.push(new order(orderItem, property1Results, property2Results));
                        }
                    });
                  }
                });
            })
        }
    });
    return orders;

这个功能很好用,我得到数据端一切正常。

然后我将函数更改为使用promises而不是Async=false, 这是 edited 函数,带有promises:

//The begin of the function- same as first one
var orders= [];
var firstPromise = $.ajax({
        url: "/API/orders/" + name,
        type: "GET"
    });
    $.when(firstPromise).done(function (orderResults) {
        var mappedOrders = $.map(orderResults, function (orderItem) {
            var secondPromise = $.ajax({
                url: "/API/orders/property/" + orderItem.id + "/type1",
                type: "GET"
            });
            $.when(secondPromise).done(function (property1Results) {
                var thirdPromise = $.ajax({
                    url: "/API/orders/property/" + orderItem.id + "/type2",
                    type: "GET"
                });
                $.when(thirdPromise).done(function (property2Results) {
                    orders.push(new order(orderItem, property1Results, property2Results));
                });
            });
        });
    });
    return orders;

以及函数调用:

self.populateOrders = function (name) {
    var mappedOrders = $.map(self.service.getOrders(name), function (item) {
        return new Order(item)
        });
    self.orders(mappedOrders);
}

新函数不起作用,我从 firstPromise 中返回一个带有反斜杠的错误 json,并且返回的 orders 对象为空。

知道我做错了什么吗?我花了这么多时间,但无法弄清楚。

提前致谢。

【问题讨论】:

  • 请分享您的其余功能(必要时删除不相关的代码)。您需要返回一个承诺而不是订单数组,并在该承诺的resolve callback 中访问您的订单数组。
  • 我编辑了我的问题。
  • 在嵌套的 Promise 中,你必须返回嵌套的 Promise。返回 secondPromise 和 thirdPromise 而不是只声明它们。
  • 另外,您必须使用 then 而不是 done 才能链接承诺。
  • 你真的需要嵌套它们吗?看起来它们可以并行运行。

标签: javascript ajax asynchronous promise


【解决方案1】:

循环内的嵌套 ajax 调用管理起来非常麻烦。你可以这样做。

  • 创建一个promise,在整个过程完成时通知调用者
  • 等待所有内部 ajax 调用解决
  • 解决您通知调用者的主要承诺

 

self.getOrders = function (name) {
    var mainDeferred = $.Deferred();
    var orders = [];
    var order = function (item, type1, type2) {
        var self = this;
        self.order = item;
        self.type1 = type1;
        self.type2 = type2;
    }

    $.ajax({
        url: "/API/orders/" + name,
        type: "GET",
        success: function (orderResults) {
            var innerwait = [];

            var mappedOrders = $.map(orderResults, function (orderItem) {
                var ajax1 = $.ajax({
                    url: "/API/orders/property/" + orderItem.id + "/type1",
                    type: "GET"
                });
                var ajax2 = $.ajax({
                    url: "/API/orders/property/" + orderItem.id + "/type2",
                    type: "GET"
                });
                $.when(ajax1, ajax2).done(function (property1Results, property2Results) {  
                    orders.push(new order(orderItem, property1Results[0], property2Results[0])))
                });
                innerwait.push(ajax1, ajax2);
            });;

            $.when.apply(null, innerwait) //make sure to wait for all ajax requests to finish
                .done(function () {
                    mainDeferred.resolve(orders); //now that we are sure the orders array is filled, we can resolve mainDeferred with orders array
                });
        }
    });

    return mainDeferred.promise();
}


self.populateOrders = function (name) {
    self.service.getOrders(name).done(function (orders) { //use .done() method to wait for the .getOrders() to resolve
        var mappedOrders = $.map(orders, function (item) {
            return new Order(item)
        });
        self.orders(mappedOrders);
    });
}

在示例中,请注意我使用$.when.apply() 来等待延迟数组。

【讨论】:

  • 虽然这应该可行,但请注意,我无法在 jsfiddle 中对此进行测试,因为您没有提供。如果你有问题,把它们包在一个 jsfiddle 中,我会看看修复它。
  • @Bergi 的评论让我意识到您的 ajax 内部 ajax 调用不需要嵌套。这在一定程度上简化了代码,因此我进行了相应的编辑。
  • 非常感谢您的明确回答,我现在就试试,会通知您,谢谢!
  • 这几乎是一个很好的答案,但你应该避免deferred antipattern!如果您只使用then 进行链接,则无需“通知”任何内容。避免 donesuccess 回调!
  • @Ozan 它正在工作但不完全,我正在获取数据并且我没有收到任何控制台错误,但是从 ajax1ajax2 返回的数据很奇怪,@ 987654329@ 看起来像:[[{"address":"test","city":"test","state":"NY","zip":null}],"success",{"readyState":4,"responseText":"[\r\n {\r\n \"address\": \"test\",\r\n \"city\": \"test\",\r\n \"state\": \"NY\",\r\n \"zip\": null\r\n }\r\n]","responseJSON"}]etc。在页面上它看起来像这样:[object Object]s, u, c, c, e, s, s 4, function (a){var b;if(2===t){if(!j){j= 等。知道是什么原因造成的吗?非常感谢!!
【解决方案2】:

最近在 chrome 52(2016 年 8 月)中引入的错误可能会导致这种行为:嵌套请求的答案被忽略。 希望不会持续太久。

https://bugs.chromium.org/p/chromium/issues/detail?id=633696

尝试添加缓存:false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2016-05-07
    • 2014-04-09
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多