javascript - 为什么我的 promise 在循环中存在计时问题,我该如何解决?

标签 javascript node.js promise

在我的爱好 Node 项目中,我对这个问题感到很抓狂。我有一个函数 (processDataSet),它正在处理一个数据数组 (inputArray) 并返回一个 promise 。该函数使用 for 循环遍历输入数组并在每一轮调用 saveObjectData 函数。此保存函数处理单个数据输入并返回 promise 。

似乎如果 saveObjectData 函数失败,processDataSet 函数会捕获返回 reject 但它自己的 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();
    });
}

在控制台输出打印:

Post processing data for the script Script1 (type: Season)
Resolve Script1
TEST PRINT Script1

似乎包含“Resolve ...”的最后一行日志在错误处理程序中的“TEST PRINT ...”之前打印。为什么会这样,我怎样才能让执行等待所有数据条目的完整解析,然后再从 processDataSet 返回?

我不完全确定在我的情况下让 processDataSet 返回 promise 是否多余,但我在故障排除过程中做了它。

最佳答案

您的 for 循环不会一一保存对象。它开始保存第一个,然后是第二个,依此类推,然后循环结束,您立即解决了您的 promise 。只有在那之后,在循环中创建的 promise 才会结算,其中一些可能会尝试拒绝已经实现的 promise。

避免 Promise constructor antipattern ,并正确地链接你的 promise 。

如果您可以立即触发所有保存以便它们同时运行,您可以使用 Promise.all 等待所有 promise :

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;
    });
}

如果你坚持顺序保存,我推荐使用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);
}

关于javascript - 为什么我的 promise 在循环中存在计时问题,我该如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52276896/

相关文章:

javascript - 如何从点击元素的相关节点获取 innerHTML/innerText?

javascript - 使用动态 javascript 变量名访问 "variable"环境变量

javascript - 如何在 Swift 中从 npm 运行 Node JS 代码

javascript - 如何在 Node.js 中正确创建 Promise

JavaScript:编写函数,将一个对象和一个函数数组作为输入参数并返回一个数组

javascript - 具有唯一 id 的 CKEDITOR 风格

javascript - 如何检测 HTML5 data-* 属性是否具有空字符串作为值?

node.js - Grunt.js 永远关注

javascript - 可选的 Promise API

javascript - 有条件的 promise 链