首页 > 解决方案 > 承诺中的 Node.js Promises 不等待 for 循环返回数据

问题描述

return Promise.all([photoArray]) 返回一个空数组,似乎没有等待 callFB 返回它的 promise,然后将其推入数组。

我不确定我做错了什么,但对于带有 for 循环和 Ifs 的 Promises 来说相对较新。

我不确定我是否使用了正确数量的 Promise,但我似乎无法让第三层 Promise.all 等待 for 循环实际完成(在这种情况下,for 循环必须仔细检查许多项目,因此这会导致一个问题,即在调用 context.done() 之前它没有触发所有项目的 callFeedback。

我也尝试将 Q.all 用于 Promise.all([photoArray]) 但无法使其正常工作。

module.exports = function (context, myBlob) {
                var res = myBlob
                var promiseResolved = checkPhoto(res,context);
                var promiseResolved2 = checkVideo(res,context); 


            Promise.all([promiseResolved, promiseResolved2]).then(function(results){
            context.log(results[0], results[1]);
 //           context.done();
            });


        });  
    };
};

function checkPhoto(res, context){
    return new Promise((resolve, reject) => {
    if (res.photos.length > 0) {
        var photoArray = [];
        for (var j = 0; j < res.photos.length; j++) {
            if (res.photos[j].feedbackId !== null){
                var feedbackId = res.photos[j].feedbackId;
                var callFB = callFeedback(context, feedbackId);                    
                Promise.all([callFB]).then(function(results){
                    photoArray.push(results[0]);
                 });        
            } else {    
                photoArray.push("Photo " + j + " has no feedback");
            }

        }

        return Promise.all([photoArray]).then(function(results){
            context.log("end results: " + results);
            resolve(photoArray);
        });
    } else {
        resolve('No photos');
    }

})
}
function checkVideo(res, context){
        return new Promise((resolve, reject) => {
            same as checkPhoto
    })
    }
function callFeedback(context, feedbackId) {
        return new Promise((resolve, reject) => {

        var requestUrl = url.parse( URL );

            var requestBody = {
                "id": feedbackId
            };

            // send message to httptrigger to message bot
            var body = JSON.stringify( requestBody );

            const requestOptions = {
            standard
            };

            var request = https.request(requestOptions, function(res) {
                var data ="";
                res.on('data', function (chunk) {
                    data += chunk
    //                context.log('Data: ' + data)
                });
                res.on('end', function () {
                resolve("callFeedback: " + true);
                })
            }).on('error', function(error) {
            });
            request.write(body);
            request.end();
            })

}

标签: javascriptnode.jsfor-looppromise

解决方案


该代码受到承诺构造反模式的影响。如果已经有一个 Promise ( Promise.all(...)),则永远不需要创建一个新的 Promise。

错误的行为是由Promise.all(...).then(...)没有被链接的承诺引起的。不处理错误并photoArray.push(results[0])导致竞争条件,因为它的评估时间晚于Promise.all([photoArray])....

如果事情应该并行处理:

function checkPhoto(res, context){
    if (res.photos.length > 0) {
        var photoArray = [];
        for (var j = 0; j < res.photos.length; j++) {
            if (res.photos[j].feedbackId !== null){
                var feedbackId = res.photos[j].feedbackId;
                var callFB = callFeedback(context, feedbackId);
                // likely no need to wait for callFB result
                // and no need for Promise.all
                photoArray.push(callFB);
            } else {    
                photoArray.push("Photo " + j + " has no feedback");
            }
        }

        return Promise.all(photoArray); // not [photoArray]
    } else {
        return 'No photos';
    };
}

callFBPromise 不相互依赖,因此可以安全地同时解决。这允许更快地处理请求。

Promise.all仅当它用于并行解决 Promise 时才有用,而原始代码试图解决结果(results[0])。

如果事情应该串行处理,该功能受益于async..await

async function checkPhoto(res, context){
    if (res.photos.length > 0) {
        var photoArray = [];
        for (var j = 0; j < res.photos.length; j++) {
            if (res.photos[j].feedbackId !== null){
                var feedbackId = res.photos[j].feedbackId;
                const callFBResult = await callFeedback(context, feedbackId);
                // no need for Promise.all
                photoArray.push(callFBResult);
            } else {    
                photoArray.push("Photo " + j + " has no feedback");
            }
        }

        return photoArray; // no need for Promise.all, the array contains results
    } else {
        return 'No photos';
    };
}

添加try..catch口味。


推荐阅读