为什么循环中我的承诺存在时间问题,我该如何解决?

qui*_*inz 2 javascript node.js promise

我在我的业余爱好节点项目中遇到这个问题.我有一个函数(processDataSet)正在处理数据数组(inputArray)并返回一个promise.该函数使用for循环遍历输入数组并saveObjectData在每一轮调用函数.此保存功能处理单个数据条目并返回承诺.

似乎如果saveObjectData函数失败,processDataSet函数捕获返回拒绝,但它自己reject似乎没有在for循环中正确调用.我认为这是一个时间问题,我不明白.查看代码下方的输出打印结果.

function processDataSet(inputArray, scriptConfig) {
    var contentType = scriptConfig.contentType;
    return new Promise(function(resolve, reject) {
        if(!Array.isArray(inputArray)) {
            return reject(new Error("Input data is not an array. Cannot process."));
        }
        if(!scriptConfig) {
            return reject(new Error("Invalid scriptConfig"));
        }
        if(!typeof contentType === "string" && !contentType instanceof String) {
            return reject(new Error("Invalid contentType for the data set. The parameter should be a string."));
        }

        console.log("Post processing data for the script " + scriptConfig.name + " (type: " + scriptConfig.contentType + ")");

        // Iterate through the input array and handle the objects one-by-one
        for (var i = 0; i < inputArray.length; i++) {
            saveObjectData(inputArray[i], scriptConfig)
            .then(() => {
                //continue;
            })
            .catch(err => {
                console.log("TEST PRINT " + scriptConfig.name);
                return reject(new Error("Processing data object failed.", err));
            });
        }
        console.log("Resolve " + scriptConfig.name);
        return resolve();
    });
}
Run Code Online (Sandbox Code Playgroud)

输出打印在控制台中:

Post processing data for the script Script1 (type: Season)
Resolve Script1
TEST PRINT Script1
Run Code Online (Sandbox Code Playgroud)

似乎包含"Resolve ..."的最后一个日志行在错误处理程序中的"TEST PRINT ..."之前打印.为什么这样做,如何在返回之前让执行等待所有数据条目的完全解析processDataSet

我不完全确定在我的情况下是否多余processDataSet才能返回承诺,但我将其作为我的故障排除的一部分.

Ber*_*rgi 5

您的for循环不会逐个保存对象.它开始保存第一个,然后是第二个,依此类推,然后循环结束,你立即解决你的承诺.只有在那之后,在循环中创建的承诺才能解决,其中一些可能会试图拒绝已经履行的承诺.

避免Promise构造函数反模式,而是正确地链接你的承诺.

如果你可以立即触发所有保存以便它们同时运行,你可以等待所有的保证Promise.all:

function processDataSet(inputArray, scriptConfig) {
    if (!Array.isArray(inputArray)) {
        return Promise.reject(new Error("Input data is not an array. Cannot process."));
    }
    if (!scriptConfig) {
        return Promise.reject(new Error("Invalid scriptConfig"));
    }
    var contentType = scriptConfig.contentType;
    if (typeof contentType !== "string") {
        return Promise.reject(new Error("Invalid contentType for the data set. The parameter should be a string."));
    }

    console.log("Post processing data for the script " + scriptConfig.name + " (type: " + scriptConfig.contentType + ")");

    return Promise.all(inputArray.map(input => {
        return saveObjectData(input, scriptConfig)
        .catch(err => {
            console.log("TEST PRINT " + scriptConfig.name);
            throw new Error("Processing data object failed.", input, err);
        });
    })).then(results => {
        console.log("Resolve " + scriptConfig.name, results);
        return;
    });
}
Run Code Online (Sandbox Code Playgroud)

如果你坚持按顺序保存它们,我建议使用async/ await.

async function processDataSet(inputArray, scriptConfig) {
    if (!Array.isArray(inputArray)) {
        throw new Error("Input data is not an array. Cannot process.");
    }
    if (!scriptConfig) {
        throw new Error("Invalid scriptConfig");
    }
    var contentType = scriptConfig.contentType;
    if (typeof contentType !== "string") {
        throw new Error("Invalid contentType for the data set. The parameter should be a string.");
    }

    console.log("Post processing data for the script " + scriptConfig.name + " (type: " + scriptConfig.contentType + ")");

    for (var input of inputArray) {
        try {
             await saveObjectData(input, scriptConfig);
        } catch (err) {
            console.log("TEST PRINT " + scriptConfig.name);
            throw new Error("Processing data object failed.", input, err);
        }
    }
    console.log("Resolve " + scriptConfig.name);
}
Run Code Online (Sandbox Code Playgroud)