2017-03-16 75 views
0

在這個稍微減少的代碼中,一次或多個星期的觀察結果每次從API下載一週,然後聚合爲rows並導出爲CSV。至少這是主意。實際發生的是Uncaught (in promise) TypeError: Cannot read property 'toString' of undefined在(未示出)exportToCsv函數中產生,因爲_promisepromiseArray推到rows即爲undefined。我錯過了什麼?爲什麼我的承諾沒有價值?

$("#downloadBtn").click(function() { 
    weeks = getWeeks(startDate.val(), endDate.val()); // array like [[startDay1, endDay1], [startDay2, endDay2], ...] 
    // start downloading the data 
    var promiseArray = []; 
    for (i=0; i< weeks.length; i++) { 
     var _promise = Q.defer(); 
     fetchDataWeek(weeks[i][0], weeks[i][1], _promise); 
     promiseArray.push(_promise) // Push this promise into the array 
    } 
    Promise.all(promiseArray).then(function() { // Wait for all promises to resolve 
     var rows = [headers]; 
     for (i=0; i < promiseArray.length; i++) { 
      rows.push(promiseArray[i]); 
     } 
     exportToCsv(fileName, rows); 
    }) 
}); 

function fetchDataWeek(startDay, endDay, _promise) { 
    url = "https://api" + startDay + endDay + ".json"; 
    $.ajax({ 
     url: url, 
     success: function(result){ 
      var weekRows = parseHistory(result); 
      _promise.resolve(weekRows); 
     }, 
     error: function (error) { 
      _promise.reject(error) // rejecting it in case of error 
     } 
    });    
} 

// Extract all data from a query response 
function parseHistory(data) { 
    var weekRows = []; 
    var days = data.history.days; 
    for (var i = 0; i < days.length; i++) { 
     dayRows = formatDay(days[i]); 
     for (var j= 0; j < dayRows.length; j++) { 
      weekRows.push(dayRows[j]); 
     } 
    } 
    return weekRows; 
} 
+1

我認爲你的主要問題是,'_promise'是** **不承諾,但一個[遞延對象(https://github.com/kriskowal/q#using-deferreds)。你需要'promiseArray.push(_promise.promise)'。你爲什麼使用'Q' **和**原生'Promise'? – Phil

+0

從[此答案以前的問題](http://stackoverflow.com/a/42817932/1706564)。我完全不熟悉jQuery和承諾 –

回答

2

一個承諾是不是一個神奇的對象「變成了」不同的值,當它被解決。當你在做rows.push(promiseArray[i]);時,你收集的是承諾對象,而不是它們包含的結果。

要訪問承諾已履行或將履行的結果,您需要鏈接一個.then(…)回調函數,您可以在其中訪問結果作爲參數。爲了從數組中的所有promise中收集結果,可以使用Promise.all,它返回另一個承諾,該承諾不僅等待所有輸入承諾,而且還用其結果值數組實現。

$("#downloadBtn").click(function() { 
    var weeks = getWeeks(startDate.val(), endDate.val()); 
    // start downloading the data 
    var promiseArray = weeks.map(function(week) { // map is simpler than a loop with `push` 
     return fetchDataWeek(week[0], week[1]); 
    }) 
    Promise.all(promiseArray).then(function(results) { // Wait for all promises to resolve 
     var rows = [headers].concat(results); 
     exportToCsv(fileName, rows); 
    }) 
}); 

function fetchDataWeek(startDay, endDay, _promise) { 
    var url = "https://api" + startDay + endDay + ".json"; 
    var jQpromise = $.ajax({ 
     url: url 
    }); 
    var qPromise = Q(jQpromise); 
    return qPromise.then(parseHistory); 
} 

function parseHistory(data) { 
    var weekRows = []; 
    var days = data.history.days; 
    for (var i = 0; i < days.length; i++) { 
     var dayRows = formatDay(days[i]); 
     for (var j= 0; j < dayRows.length; j++) { 
      weekRows.push(dayRows[j]); 
     } 
    } 
    return weekRows; 
} 
1

您可以接收then處理你的承諾的結果:

Promise.all(promiseArray).then(function (results) { // Wait for all promises to resolve 
    var rows = [headers].concat(results); 
    exportToCsv(fileName, rows); 
    })