Why is no value returned from my Promise?

时光毁灭记忆、已成空白 提交于 2019-12-12 02:18:12

问题


In this slightly reduced code, one or more weeks of observations are downloaded a week at a time from an API, and aggregated into rows and exported to CSV. At least that is the idea. What is actually happening is that an Uncaught (in promise) TypeError: Cannot read property 'toString' of undefined is raised in the (not shown) exportToCsv function because the _promise pushed from promiseArray to rows is coming out as undefined. What am I missing?

$("#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:


A promise is not a magical object that "becomes" a different value when it is resolved. When you were doing rows.push(promiseArray[i]);, you were collecting promise objects not the results that they contained.

To access the result that a promise was or will be fulfilled with, you need to chain a .then(…) callback to it in which you can access the result as the parameter. To collect the results from all the promises in the array, you use Promise.all, which returns another promise that not only waits for all the input promises but also fulfills with an array of their result values.

$("#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;
}



回答2:


You can receive the result of your promises in the then handler:

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


来源:https://stackoverflow.com/questions/42823678/why-is-no-value-returned-from-my-promise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!