2017-02-07 48 views
-1

因此,我已經做了很多這方面的疑難解答,我的頭撞牆。大多數情況下,我對承諾及其工作方式非常熟悉,並已將其用於少數項目。我遇到了讓我所有的承諾,在使從谷歌日曆API和腳本來計算結果數組的長度回調函數來使用不同的日曆數據多次打電話給做完了一點小麻煩。下面是相關代碼:jQuery當不按預期延期承諾

(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); 

基本問題是要$.when的最後通話,因爲我在等待我承諾要完成的陣列。 $.when似乎沒有工作,因爲如果我嘗試在$.when回調中將calendarData數組記錄到控制檯,它將返回一個沒有計算長度的數組。我已經能夠找出如何做到這一點的唯一方法是在回調使用setTimeout,並將其設置爲圍繞2000毫秒,但這並不是理想的,因爲這取決於網絡連接性,API可用性等等,接收所有數據的時間可能完全不同。

正如我所看到的在控制檯的一個想法,我得到這個「長少」陣列時,我嘗試登錄,結果在$.when回調,無法通過,因爲腳本似乎被迭代認爲這是空:

array with no length

任何想法,我做錯了什麼嗎?預先感謝您的幫助。

+0

1)deferred.then返回一個新的承諾,而不是你返回的數組。 2)在解決getcalendars後,您將無法訪問該數組。 3)將您的承諾數組放在.then的範圍之外,然後使用getcalendars.then填充它。使用另一個外部延遲,你將從getcalendars.after中解析出最終的promise後推送到數組,然後用它來執行.apply到數組 –

+0

'$ .when()'實際上是腦死亡,使用時更是如此用jQuery Ajax調用。它不解析爲數組。它解析爲N個單獨的參數,每個參數都可能是一個數組。爲了處理任意數量的結果,你必須在'.when(...)。then(fn)''中處理傳遞給'fn'的'arguments'對象。研究jQuery文檔中的'.when()'示例,特別是在使用Ajax調用時。 – jfriend00

回答

0

你必須在你的代碼是如何工作的若干結構性問題。我發現的問題:

  1. 請勿使用已棄用的.success()。使用.then()
  2. 你試圖從一個承諾回報承諾的數組。相反,使用$.when()那裏返回解析結果的陣列中的單個承諾。
  3. $.when()在它如何返回結果方面非常好用。它返回它們作爲單獨的參數,而不是作爲結果的陣列(它不象標準ES6確實Promise.all()工作)。
  4. 如果您直接使用jQuery ajax承諾$.when(),jQuery Ajax調用將解析爲三個參數並與$.when()進行非常奇怪的交互。
  5. 您在更高範圍的變量中依賴副作用,而不僅僅是解析所需數據的承諾(不需要更高範圍的變量來跟蹤數據)。這使得代碼更大量的自包含的,可重複使用且不受競爭條件(如果不止一個地方使用)。
  6. 重組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); 
}); 

然後,重要的是一個jQuery Ajax調用不能解決爲單個值或者之上,它解析爲三個值。所以,當你通過N jQuery時,ajax承諾$.when(),你得到N個參數給你的回調函數,其中每個參數都是一個由三個值組成的數組(jQuery Ajax承諾的三個值)。


所以,如果你想處理在$.when()承諾結果任意數量的,你必須使用傳遞給你的回調arguments對象並重復這一點。

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); 

或者,你可以像我一樣在我的推薦代碼上方和轉換參數反對的結果數組,所以你可以在上面正常使用陣列功能。


另外,.success()已被棄用。你不應該使用它。改爲使用.then()

+0

爲什麼downvote?請解釋。 – jfriend00

+0

增加了關於編碼邏輯結構問題的重要附加信息。 – jfriend00

+0

@brianjohnhanna - 這是否爲你解釋事情並回答你的問題? – jfriend00

-2

有沒有和他們玩過一段時間,但你應該能夠接受並運行它。

/* 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}); }) 
+1

這是如何解決問題的? – jfriend00

+0

因爲它確保他的所有承諾在他嘗試訪問它們之前都完好無損。時間的設置只在所有的承諾都在數組後完成。而deferreds []現在處於可訪問的範圍內。 –