Javascript jQuery在未按预期使用延迟承诺时

Javascript jQuery在未按预期使用延迟承诺时,javascript,jquery,arrays,promise,deferred,Javascript,Jquery,Arrays,Promise,Deferred,所以我在这方面做了很多故障排除,我的头撞到了墙上。在大多数情况下,我非常熟悉承诺及其工作方式,并在一些项目中使用过它们。在从Google calendar API调用不同的日历数据和脚本来计算回调函数中使用的结果数组的长度时,我遇到了一些麻烦,无法完成所有的承诺。以下是相关代码: (function($){ var baseUrl = 'https://www.googleapis.com/calendar/v3/calendars/', apiKey = 'xxxxxx

所以我在这方面做了很多故障排除,我的头撞到了墙上。在大多数情况下,我非常熟悉承诺及其工作方式,并在一些项目中使用过它们。在从Google calendar API调用不同的日历数据和脚本来计算回调函数中使用的结果数组的长度时,我遇到了一些麻烦,无法完成所有的承诺。以下是相关代码:

(function($){
    var baseUrl = 'https://www.googleapis.com/calendar/v3/calendars/',
        apiKey = 'xxxxxxxxxxxx',
        calendarData = [],
        events = [],
        allCalendars = [],
        eventsToDisplay = 9;

    /* Get all the calendars that we have registered */
    function getCalendars() {
        return $.getJSON(ajaxurl, {action: 'wps_get_calendars'});
    }

    /*  Get the events for a calendar by the calendar ID */
    function getCalendarEvents(calendarID) {
        return $.getJSON(baseUrl + calendarID + '/events', {
            maxResults: '4',
            orderBy: 'startTime',
            timeMin: moment().format(),
            singleEvents: true,
            key: apiKey
        }).success(function(data){
            calendarData.push(data.items);
    });

    /*  Create a collection of promises */
    var promises = getCalendars().then(function(calendars){
        var deferreds = [];
        calendars.forEach(function(calendar){
            deferreds.push( 
                getCalendarEvents(calendar.googleCalendarId)
            );
        });
        return deferreds;
    });

    /*  Wait until all the promises have completed, then sort the events */
    $.when.apply($, promises).then(concatEvents);

})(jQuery);
基本上,问题是在最后一次调用
$时。当我在等待一系列承诺时,我必须完成<代码>$。当
似乎不起作用时,因为如果我尝试将
日历数据
数组记录到
$中的控制台。当
回调时,它返回一个没有计算长度的数组。我能弄清楚如何做到这一点的唯一方法是在回调中使用
setTimeout
,并将其设置为大约2000毫秒,但这并不理想,因为根据网络连接、API可用性等,接收所有数据的时间可能完全不同

正如我在控制台中看到的一样,当我尝试在
$中记录结果时,我得到了这个“长度较少”的数组。当
回调时,由于脚本似乎认为它是空的,因此无法对其进行迭代:


知道我做错了什么吗?提前感谢您的帮助。

已经有一段时间没有玩过它们了,但您应该可以带着它跑步

/*  Create a collection of promises */
var control = $.Deferred();
var deferreds = [];
getcalendars().done(function(calendars){
    calendars.forEach(function(calendar){
        deferreds.push( 
            getCalendarEvents(calendar.googleCalendarId)
        );
    });
    control.resolve();
});

control.done(function(){
  /*  Wait until all the promises have completed, then sort the events */
  $.when.apply($, deferreds).done(function() {concatEvents});    })

在代码的工作方式方面,您有几个结构性问题。我发现的问题:

  • 不要使用不推荐使用的
    .success()
    。使用
    .then()
  • 您试图从承诺中返回一系列承诺。相反,使用
    $.when()
    返回解析为结果数组的单个承诺
  • $.when()
    在返回结果的方式上非常不稳定。它将它们作为单独的参数返回,而不是作为结果数组返回(它不像ES6标准
    Promise.all()
    那样工作)
  • jQuery Ajax调用解析为三个参数,并与
    $进行非常奇怪的交互。如果直接使用jQuery Ajax,则会与
    $.when()
    进行交互
  • 您依赖于范围更大的变量的副作用,而不仅仅是用所需的数据解决承诺(不需要范围更大的变量来跟踪数据)。这使得代码更加独立和可恢复,并且不受竞争条件的约束(如果在多个地方使用)
  • 重新构造
    getCalendar()
    ,使其返回解析为日历数组的单个承诺,从而使其使用更加简单
  • 这将得到您想要的结果,并消除一些范围更大的变量和您所依赖的副作用

    (function($){
        var baseUrl = 'https://www.googleapis.com/calendar/v3/calendars/',
            apiKey = 'xxxxxxxxxxxx',
            events = [],
            eventsToDisplay = 9;
    
        /* Get all the calendars that we have registered */
        function getCalendars() {
            return $.getJSON(ajaxurl, {action: 'wps_get_calendars'}).then(function(calendars){
                var promises = calendars.map(function(calendar) {
                    return getCalendarEvents(calendar.googleCalendarId);
                });
                return $.when.apply($, promises).then(function() {
                    // convert arguments to a single array as our resolved value
                    return [].slice.call(arguments);
                });
            });
        }
    
        /*  Get the events for a calendar by the calendar ID */
        function getCalendarEvents(calendarID) {
            return $.getJSON(baseUrl + calendarID + '/events', {
                maxResults: '4',
                orderBy: 'startTime',
                timeMin: moment().format(),
                singleEvents: true,
                key: apiKey
            }).then(function(data){
                // make resolved value be just data.items
                return data.items;
        });
    
        /*  get all calendars */
        getCalendars().then(function(calendars){
            // process array of calendars here
            console.log(calendars);
        });
    
    })(jQuery);
    

    此外,很容易被
    $.when()
    的工作方式弄糊涂。这里有一些一般信息来解释

    $.when()
    不解析为结果数组。相反,它将每个结果作为单独的参数传递给回调。所以,如果你有三个结果,那么它会这样做:

    $.when(p1, p2, p3).then(function(r1, r2, r3) {
        console.log(r1, r2, r3);
    });
    
    然后,最重要的是,jQueryAjax调用也不会解析为单个值,而是解析为三个值。因此,当您将N个jQuery ajax承诺传递给
    $时,您将得到N个回调参数,其中每个参数是三个值(jQuery ajax承诺中的三个值)的数组


    因此,如果要在
    $中处理任意数量的promise结果,则必须使用传递到回调的
    参数
    对象并对其进行迭代

    function processWhenResults() {
        for (var i = 0; i < arguments.length; i++) {
            // output each ajax result
            // arguments[i] is an array of results for each corresponding ajax call
            // arguments[i][0] is the actual Ajax result value
            console.log(arguments[i][0]);
        }
    }
    
    
    $.when.apply($, promises).then(processWhenResults);
    
    函数processWhenResults(){
    for(var i=0;i
    或者,您可以像我在上面建议的代码中所做的那样,将arguments对象转换为一个结果数组,这样您就可以对其使用普通数组函数



    此外,
    .success()
    已被弃用。你不应该使用它。改用
    .then()

    1)deferred。然后返回一个新的承诺,而不是返回的数组。2) 在解决getcalendars之前,您将无法访问阵列。3) 将您的promise数组置于.then范围之外,并使用getcalendars.then填充它。使用另一个将从getcalendars解析的外部延迟。将最终承诺推送到数组后,然后使用它来执行。应用到数组
    $。当()
    真的是脑死亡时,与jQuery Ajax调用一起使用时更是如此。它不解析为数组。它解析为N个独立的参数,每个参数可能是一个数组。要处理任意数量的结果,您必须在
    $中处理传递给
    fn
    参数
    对象。当(…)。然后(fn)
    。研究jQuery文档中的
    $.when()
    示例,尤其是与Ajax调用一起使用时。因为它可以确保在他尝试使用when访问承诺之前,所有承诺都完好无损。只有在数组中包含所有承诺后,才能设置when。延迟[]现在在一个可访问的范围内。添加了关于编码逻辑结构问题的重要附加信息。@brianjohnhanna-这为您解释了事情并回答了您的问题吗?我还没有机会尝试它,但我感谢您的解释!我会试试,然后回来汇报