2017-03-16 37 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); 
    })