Javascript 承诺数组中的承诺数组
我有一个包含书籍数据的数组。我必须在数组中循环并进行服务调用以获取每本书的详细信息,并且每本书的数据都有与该书相关联的附件id,并进行服务调用以获取每本书的相关附件 这里的问题是承诺。所有不等待附件承诺得到解决Javascript 承诺数组中的承诺数组,javascript,promise,Javascript,Promise,我有一个包含书籍数据的数组。我必须在数组中循环并进行服务调用以获取每本书的详细信息,并且每本书的数据都有与该书相关联的附件id,并进行服务调用以获取每本书的相关附件 这里的问题是承诺。所有不等待附件承诺得到解决 function ExportbooksData(books) { return new Promise((resolve, reject) => { if (books && books.length > 0) { let aPr
function ExportbooksData(books) {
return new Promise((resolve, reject) => {
if (books && books.length > 0) {
let aPromises = [];
for (let i = 0; i < books.length; i++) {
const id = books[i].id;
const name = books[i].name;
aPromises.push(this.getBooksData(name, id, null).then(results => {
let aAttachmentPromises = [];
Object.entries(results).forEach(([key, value]) => {
let fieldName = key;
if (value.constructor === Array && value.length > 0) {
aAttachmentPromises.push(this.getAttachments(fieldName).then(fileContent => {
}))
}
});
}));
}
// Resolve when all are done!
Promise.all(aPromises)
.then(results => resolve(results))
.catch(error => reject(error));
}
})
}
您建立了一个AttachmentPromises,但没有返回它,因此apropmises.push总是将一个立即解析为undefined的承诺推送到您正在等待的数组中。按如下方式更改代码:
aPromises.push(
this.getBooksData(name, id, null).then(results => {
let aAttachmentPromises = [];
Object.entries(results).forEach(([key, value]) => {
let fieldName = key;
if (value.constructor === Array && value.length > 0) {
aAttachmentPromises.push(this.getAttachments(fieldName)
.then(fileContent => {})
.catch(err => {
if (err == "minor") console.log("Ignoring error",err);
else throw err;
})
);
}
});
return Promise.all(aAttachmentPromises); // <--- here!
})
);
除此之外,您还可以简化函数。您不需要将所有内容都封装在一个新的Promise对象中,使用一个变量来保存一个只使用一次的值是没有帮助的。此简化版本更易于阅读/维护:
function ExportbooksData(books) {
let aPromises = [];
for (let i = 0; books && i < books.length; i++) {
aPromises.push(
this.getBooksData(books[i].name, books[i].id, null).then(results => {
let aAttachmentPromises = [];
Object.entries(results).forEach(([key, value]) => {
if (value.constructor === Array && value.length > 0) {
aAttachmentPromises.push(this.getAttachments(key).then(fileContent => {}));
}
});
return Promise.all(aAttachmentPromises);
})
);
}
return Promise.all(aPromises);
}
我今晚在澳大利亚布里斯班的布里斯JS会议现场重构了这个。这是我做这件事的视频,并解释了变化: 这是一份包含您的版本和重构以及模拟服务的回购协议:
有关如何处理失败的讨论,请参阅本文:不需要在新的承诺中包装,承诺。所有本身都会返回一个承诺。避免使用新的承诺!我不认为仅仅返回aAttachmentPromises实际上就能解决这个数组中的所有承诺,因为apropmises现在变成了承诺数组。你是对的@SujeetAgrahari返回应该是一个承诺。我在返回附件后编辑了我的回答,保证它工作正常。但是,如果附件承诺中的一个失败,那么它将无法获取剩余书籍的任何getBooksData。是的,如果要忽略个别失败,可以添加.catch语句,并确定是否应根据具体情况重新抛出失败。但您描述的是Promise.all Works我尝试添加如下捕获返回Promise.AllAttachmentPromises.thenresults=>resolveresults.catcherror=>rejecterror;同样的道理。在此更改之后,我也不会获得成功附件。您应该将筛选器放在映射之前,这样您就不需要映射到未定义的。
function getAttachmentsForBookWithMetadataArray(bookdata) {
return Object.entries(bookdata)
.filter(([_, value]) => value.constructor === Array && value.length > 0)
.map(([fieldname, _]) => getAttachments(fieldname));
}
function getAttachmentsForBook(book) {
return getBookData(book).then(getAttachmentsForBookWithMetadataArray);
}
function ExportbooksData(books) {
return !books || !books.length > 0
? Promise.reject(new Error("Did not get an array with 1 or more elements"))
: Promise.all(books.map(getAttachmentsForBook));
}