javascript - 为什么我的承诺在循环中存在时间问题,我该如何解决?
问题描述
在我的爱好节点项目中,我对这个问题非常恼火。我有一个函数 ( processDataSet
),它正在处理一个数据数组 ( inputArray
) 并返回一个承诺。该函数使用 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();
});
}
在控制台中输出打印:
Post processing data for the script Script1 (type: Season)
Resolve Script1
TEST PRINT Script1
似乎在错误处理程序中的“TEST PRINT ...”之前打印了最后一个日志行,包括“Resolve ...”。为什么会这样,我怎样才能让执行在返回之前等待所有数据条目的完全解析processDataSet
?
我不完全确定在我的情况下processDataSet
返回承诺是否是多余的,但我把它作为我的故障排除的一部分。
解决方案
您的for
循环不会一一保存对象。它开始保存第一个,然后是第二个,依此类推,然后循环结束,您立即解决您的承诺。只有在那之后,在循环中创建的 Promise 才会解决,其中一些可能会尝试拒绝已经实现的 Promise。
避免使用Promise
构造函数 antipattern,而是正确地链接你的 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;
});
}
如果您坚持按顺序保存它们,我建议使用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);
}
推荐阅读
- c# - 禁用重构后使用 AxWebBrowser 时出错
- node.js - node.js 中的 AWS lambda 配置
- azure - 什么是红移提取数据类型的替代方案
- rest - java1.6中javax.ws.rs.core.Response转换为字符串
- c# - 将我的 Powershell 脚本转换为 c# Windows 窗体
- database-design - 时间序列的最优 Cassandra 模式
- netlify - 如何在 netlify.toml 配置中插入环境变量
- elasticsearch - 无法创建 PreBuiltXPackTransportClient x-pack 弹性搜索
- python - impyla - as_pandas - 空数据框
- javascript - 如何使用 Google Apps 脚本从网络中的公共 CSV 过滤数据?