【问题标题】:Orchestrating Nested AJAX Calls Within Each Loop Before Chart Is Drawn (JQuery)在绘制图表之前编排每个循环内的嵌套 AJAX 调用(JQuery)
【发布时间】:2014-11-28 01:46:13
【问题描述】:

这几天我一直在寻找这个问题的答案,但没有运气。

我正在尝试从通过 ajax 调用到 JSON REST Api 收集的数据构建图表。我使用 morris.js 来构建我的图表。图表的数据是通过 3 个嵌套的 ajax 调用收集的。第一个 ajax 调用检索包含任务的列表,成功时循环迭代结果并对每个结果进行 ajax 调用。并在这些调用成功时检索数据以构建图表。

在最后一个成功函数中,for loop 运行以构建包含图表数据的数组。

这些数据被推入图表的参数数组 (morris.js)。

所以 3 个嵌套的 ajax 调用,在第一次调用之后有一个 $.each 循环。

我的问题是每次 ajax 迭代都会生成图表。我一直在尝试将图表函数 (Morris.Donut(params);) 移到循环之外,但没有运气。

我的代码:

var arr = [];
var counts = [];
var test = [];
$.ajax({
    url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests?$filter=TaskStatusValue%20eq%20%27Not%20Started%27",
    headers: {
        'accept': 'application/json;odata=verbose',
        'content-type': 'application/json;odata=verbose'
    },
    success: function(data) {
        $.each(data.d.results, function(a, data) {
            $.ajax({
                url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(" + data.RequesterId + ")/CreatedBy",
                headers: {
                    'accept': 'application/json;odata=verbose',
                    'content-type': 'application/json;odata=verbose'
                },
                success: function(data2) {
                    $.ajax({
                        url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(" + data.AssignedToId + ")/AssignedTo",
                        headers: {
                            'accept': 'application/json;odata=verbose',
                            'content-type': 'application/json;odata=verbose'
                        },
                        success: function(data3) {
                            var params = {
                                element: 'taskchart',
                                data: [],
                                colors: ['#b85f28', '#d46125', '#CE4E00']
                            };
                            $(".inner").prepend('<p>'+data.Request +' <br>Submitted by: '+data2.d.Name+'<br>Assigned to: '+data3.d.Name+' | Due in: '+data.DueInDays+' day(s)</p>');
                            var indexOfName = arr.indexOf(data3.d.Name);
                            if (indexOfName == -1) {
                                arr.push(data3.d.Name);
                                counts.push(1);
                            } else {
                                counts[indexOfName] ++;
                            }
                            for (var i in arr, counts) {
                                test = {
                                    'label': '' + arr[i] + '',
                                    'value': counts[i]
                                }
                                params.data.push(test);
                            }
                            Morris.Donut(params);
                        }
                    })
                }
            })
        })
    }
})

我知道这段代码看起来有点乱,但我似乎无法更好地构建它。关于在 ajax 调用完成加载数据后如何构建图表的任何建议?

我真的是撞墙了。

【问题讨论】:

  • 您的data2 没有在任何地方使用。
  • 另外,由于这些基本上是顺序调用,您可以尝试将所有$.ajax 调用的async 选项设置为false。 $.each 循环中的事情可能会出现问题。
  • 我的错误。我之前确实使用它来显示其他一些数据,但我没有包括在内,因为它与我的问题无关。将立即编辑。
  • 异步似乎没有什么不同。如何正确地将成功调用与回调联系起来?比如function ajax1(data){ $.ajax({ url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests?$filter=TaskStatusValue%20eq%20%27Not%20Started%27", headers: { 'accept': 'application/json;odata=verbose', 'content-type': 'application/json;odata=verbose' }, ajax2(); }) }; 这样对吗?

标签: javascript jquery ajax morris.js


【解决方案1】:

问题概述

在仔细查看您的代码之后,您的图表在您的 $.each 函数中为每次迭代重新构建的原因是因为您的 Morris.Donut(params); 在循环中最深嵌套的 success 回调中被调用(duh ?)。并且将 Morris.Donut(params); 移到 $.each 函数之外将无法工作,这仅仅是因为嵌套 ajax 调用的异步性质,即在 ajax 调用完成之前,对 $.each 的调用可能退出并调用 Morris.Donut(params); .

更简单的替代(服务器端)解决方案

在向您展示一些 javascript 代码之前,我建议如果您可以控制服务器端 API 代码,您应该考虑将所有这些复杂性移到那里;即创建一个接受TaskStatusValue 输入的新Web 服务,并返回满足此条件的IT 请求以及构建图表所需的任何其他信息(请求者姓名、受让人姓名等)。我认为本质上,这就是您的 JS 代码正在尝试做的事情。

正如我在之前的评论中提到的,您的嵌套 AJAX 调用依赖于父 AJAX 调用的结果,这基本上归结为发出同步请求,从而违背了异步调用的目的。

JQuery 解决方案 (TL;DR)

话虽如此,如果您绝对必须在客户端执行所有操作,我们需要将 jQuery.deferred 对象数组传递给 jQuery.when 函数,这样您的图表将仅在您完成所有异步操作后绘制通话已完成。

还有其他更简单、更好的方法来做到这一点。但这是我的解决方案....

代码重构

将两个嵌套的 AJAX 调用提取到一个单独的函数中,如下所示。该函数将返回$.ajax函数返回的Deferred对象:

function retrieveITRequestsFrom(url){
  return $.ajax(url, {
           headers: {
             'accept': 'application/json;odata=verbose',
             'content-type': 'application/json;odata=verbose'
           },
           /* etc */
         });
}

在您的第一个 success 回调中使用 TaskStatusValue=NotStarted 获取所有 IT 请求后,将您稍后将进行的所有 AJAX(延迟对象)调用添加到这样的数组中:

deferreds = []
$.each(data.results, function(){
    var requesterURL = 'http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(' + this.RequesterId + ')/CreatedBy';
    deferreds.push(retrieveITRequestsFrom(requesterURL));

    var assigneeURL = 'http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(' + this.AssignedToId + ')/AssignedTo';
    deferreds.push(retrieveITRequestsFrom(assigneeURL));        
});

最后,您可以将这个Deferred 对象数组传递给$.when 函数。

$.when.apply($, deferreds)
 .then(function(){
     $.each(arguments, function(){
         console.log(this[0]);
     });
})

$.each 函数中的伪数组arguments 应该包含从所有 ajax 调用中收集的所有结果。您可以在then 回调中绘制图表。

我使用这个fiddle 进行了实验,使用了一些假数据。

【讨论】:

    【解决方案2】:
    1. 将最后两个 ajax 调用更改为同步(通过添加选项 异步:假)
    2. 将 params 对象移至声明部分
    3. 将 morris.donut(params) 行移动到第一个 ajax 调用成功函数的末尾 我已经通过这些更改更改了上面的整个代码块(你的问题的代码)
    var arr = [];
        var counts = [];
        var test = [];
        var params = {
            element: 'taskchart',
            data: [],
            colors: ['#b85f28', '#d46125', '#CE4E00']
        };
        $.ajax({
            url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests?$filter=TaskStatusValue%20eq%20%27Not%20Started%27",
            headers: {
                'accept': 'application/json;odata=verbose',
                'content-type': 'application/json;odata=verbose'
            },
            success: function(data) {
                $.each(data.d.results, function(a, data) {
                    $.ajax({
                        async: false,
                        url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(" + data.RequesterId + ")/CreatedBy",
                        headers: {
                            'accept': 'application/json;odata=verbose',
                            'content-type': 'application/json;odata=verbose'
                        },
                        success: function(data2) {
                            $.ajax({
                                async: false,
                                url: "http://helpdesk.site.com/IT/_vti_bin/ListData.svc/ITHelpdeskRequests(" + data.AssignedToId + ")/AssignedTo",
                                headers: {
                                    'accept': 'application/json;odata=verbose',
                                    'content-type': 'application/json;odata=verbose'
                                },
                                success: function(data3) {
    
                                    var indexOfName = arr.indexOf(data3.d.Name);
                                    if (indexOfName == -1) {
                                        arr.push(data3.d.Name);
                                        counts.push(1);
                                    } else {
                                        counts[indexOfName] ++;
                                    }
                                    for (var i in arr, counts) {
                                        test = {
                                            'label': '' + arr[i] + '',
                                            'value': counts[i]
                                        }
                                        params.data.push(test);
                                    }
    
                                }
                            })
                        }
                    })
                })
                 Morris.Donut(params);
            }   
        })
    

    【讨论】:

    • 这是一大堆代码,没有解释发生了什么变化或为什么它应该有所作为。这是一个找不同的游戏,而不是一个答案。
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多