【问题标题】:How exactly works this Promise.all() statement in my code?这个 Promise.all() 语句在我的代码中究竟是如何工作的?
【发布时间】:2021-04-11 02:31:31
【问题描述】:

我是 JavaScript 技术和 RxJS 的新手,我对这段代码的工作原理有以下疑问。它取自我正在处理的一个项目,它运行良好,但我需要了解 Promise.all() 的确切工作原理以及它在此代码中的使用方式。

所以基本上我有这个方法用来在 Firebase Store 上保存多个文件:

public async saveAsset(parameters: any, filesList: any[]) {
    console.log("saveAsset() START, parameters: ", parameters);

    if(filesList != null) {
      //return await this.uploadFileIntoFirebaseStore(filesList);

      let files: any[] = [];
      if (filesList) {                            // If exist files that have to be updated

        /**
         * Retrieve files URLs list on Firebase Storage.
         * uploadFileIntoFirebaseStore() receive the files list to be uploaded and return a Promise resolving 
         * an array of string representing the URLs where of the uploaded files.
         * 
         */
        files = (await Promise.all(this.uploadFileIntoFirebaseStore(filesList)))
          .map(url => {
            console.log("UPLOADED URL: ", url);
            return {
              url
            };
          });
      }

    }
    else {
      //return await this.firestore.collection('assets').doc().set(parameters);
    }

}

基本上,我的 saveAsset() 方法接收 filesList 参数,该参数是用户上传的必须保存在 Firebase 存储上的文件的列表。保存文件后,我必须存储文件 URL。

为了保存这些文件,它使用了返回 Promise[]uploadFileIntoFirebaseStore() 方法。所以它返回一个由 n 个 Promise 对象组成的数组。

所以,如果我很好地理解了 Promise 概念(如果我做错了断言,请纠正我),我的 uploadFileIntoFirebaseStore() 方法正在返回一个 Promise 类型的对象,它基本上可以做两种不同的事情:

  1. 可以解析为字符串数组(其中每个字符串代表 Firebase 存储上上传文件的 URL)。
  2. 发生错误时被拒绝(我认为如果文件上传失败可能会发生这种情况)。

因此,根据我对 Promise.all() 方法的使用的理解,它会在我的数组的所有承诺都得到解决之后执行一些操作。所以在我的代码中我有:

await Promise.all(this.uploadFileIntoFirebaseStore(filesList))

如果我很好理解这个概念,这意味着我的 uploadFileIntoFirebaseStore 在 Firebase 存储中执行我的文件的有效上传并返回一个 Promise 数组,其中每个 Promise 都可以在上传 URL 中解析。这种行为是异步的,因为文件可以在其他文件之后或之前上传。这里是第一个疑问:我的 Promise 数组立即返回,然后 Promise 开始以异步方式解决,或者在相关文件开始上传时发出 Promise 对象(类似于 Observable)。我认为行为是第一个,但我不确定。

第二个疑问与Promise.all()方法前面的await关键字有关。这意味着这是一个 async 方法?据我了解,await 关键字只能用于异步方法。

最后一个疑问是:查看各种教程和文档,我发现经常是这样的:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

基本上我有 n 个 Promise 对象,它们作为数组传递给 Promise.all() 方法作为数组,然后我有 then() 方法执行箭头函数,当所有的 Promise 对象数组被解析(我也可以让 catch() 方法在被拒绝的情况下做一些事情)。

这与我的代码完全不同,在我的代码中我没有 then() 方法,当我的所有承诺都得到解决时,该方法会执行某些操作。相反,我的代码使用(已解决?)承诺列表中的 RxJS ma​​p() 运算符。

据我所知,此 map() 运算符迭代返回的已解决承诺,其中包含相关文件的 url,以便在控制台中打印它并将其作为 Observable 返回(在我看来 map() 总是返回一个 Observable,对吗?)

这种语法究竟是如何工作的?为什么不使用 then()?

【问题讨论】:

  • “这意味着这是一个异步方法?” - 是的,看第一行:public async saveAsset。您可以改用.then,它们是可互操作的; async/await 只是承诺的语法糖。 (await Promise.all(arrayOfPromises)) 解析为数组; map 不是 RxJS 函数,是数组方法。
  • 我建议阅读例如如果您不清楚async/await 语法和承诺之间的交互,stackoverflow.com/q/34401389/3001761 以及与之相关的各种资源。
  • async & await 只是promise & then 的语法糖。他们真的是一回事。异步函数返回一个承诺,然后 await 将函数的其余部分放在事件循环中,并在完成后将检索到的值传递给它(.then(()=>{}) 的工作原理)。

标签: javascript typescript promise rxjs angular-promise


【解决方案1】:

这是一个很大的问题,如果我没有回答所有方面,请见谅。仔细看括号个数:

files = (await Promise.all(this.uploadFileIntoFirebaseStore(filesList)))

这里,await(参见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)的语法将等待传递给 Promise.all 的 Promise。

这意味着,上面的括号将最终评估为一个数组(不是一个承诺)。

使用字符串数组,可以调用map,因为这现在只是一个字符串数组。

如果你想使用then,你可以这样做:

Promise.all(...).then(urls => urls.map(...))

我希望这能回答您问题的基本方面。

【讨论】:

  • 是的,现在很清楚了。如果我的 Promise.all() 方法是立即接收所有 Promise 对象的数组而不是等待所有承诺的解决,那么我唯一无法理解的事情是(因此异步行为意味着不同的承诺可以在不同的时间),或者如果 Promise 对象在不同的​​时间“到达”,比如 Observable 行为
  • @AndreaNobili 承诺只解决一次,这与 observable 不同 - Promise.allfirst 承诺拒绝时拒绝,或在 all 已解决时解决。见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
【解决方案2】:

Promise.all

它将接受一组 promise 并并行执行它们。 它遵循all or none

的机制

Promise.all([ ...]).then(console.log) 如果所有的promise都履行就会执行,否则就会执行catch Promise.all([ ...]).catch(console.log)

还有一种方法Promise.allSettled 即使其中一个承诺失败,这也将视为成功。返回数据包含所有带有雕像的结果

语法:-

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.all(promises)
  .then((results) => results.forEach((result) => console.log(result)))
  .catch(console.error);

【讨论】:

    猜你喜欢
    • 2013-12-05
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    相关资源
    最近更新 更多