Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/451.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 承诺数组中的承诺数组_Javascript_Promise - Fatal编程技术网

Javascript 承诺数组中的承诺数组

Javascript 承诺数组中的承诺数组,javascript,promise,Javascript,Promise,我有一个包含书籍数据的数组。我必须在数组中循环并进行服务调用以获取每本书的详细信息,并且每本书的数据都有与该书相关联的附件id,并进行服务调用以获取每本书的相关附件 这里的问题是承诺。所有不等待附件承诺得到解决 function ExportbooksData(books) { return new Promise((resolve, reject) => { if (books && books.length > 0) { let aPr

我有一个包含书籍数据的数组。我必须在数组中循环并进行服务调用以获取每本书的详细信息,并且每本书的数据都有与该书相关联的附件id,并进行服务调用以获取每本书的相关附件

这里的问题是承诺。所有不等待附件承诺得到解决

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