什么时候使用promise.all()?

时间:2016-07-04 08:30:57

标签: javascript design-patterns promise

这更像是一个概念性问题。我理解Promise设计模式,但无法找到可靠的来源来回答我关于promise.all()的问题:

使用promise.all()

的正确方案是什么?

OR

是否有使用promise.all()的最佳做法?理想情况下,只有当所有的promise对象都是相同或相似类型时才能使用它吗?

我唯一能想到的是:

  • 如果您想要解决承诺 ,如果所有的承诺对象解决了,那么请使用promise.all(),如果有人拒绝,则使用拒绝。

9 个答案:

答案 0 :(得分:42)

我不确定是否有人真正给出了关于何时使用Promise.all()(以及何时不使用它)的最通用的解释:

  

使用promise.all()

的正确方案是什么
只要您有多个承诺并且您的代码想知道这些承诺所代表的所有操作何时成功完成,

Promise.all()就很有用。什么是异步操作并不重要。如果它们是异步的,由promises表示,并且您的代码想要知道它们何时完成,那么Promise.all()就是为了完成它而构建的。

例如,假设您需要从三个单独的远程API调用中收集信息,并且当您获得所有三个API调用的结果时,则需要使用所有三个结果运行一些其他代码。这种情况对于Promise.all()来说是完美的。你可以这样:

Promise.all([apiRequest(...), apiRequest(...), apiRequest(...)]).then(function(results) {
    // API results in the results array here
    // processing can continue using the results of all three API requests
}, function(err) {
    // an error occurred, process the error here
});

Promise.all()可能最常用于相似类型的请求(如上例所示),但没有理由需要它。如果您有不同的情况需要发出远程API请求,请读取本地文件并读取本地温度探测器,然后当您获得来自所有三个异步操作的数据时,您希望对所有数据进行一些处理三,你会再次使用Promise.all()

Promise.all([apiRequest(...), fs.readFileAsync(...), readTemperature(...)]).then(function(results) {
    // all results in the results array here
    // processing can continue using the results of all three async operations
}, function(err) {
    // an error occurred, process the error here
});

另一方面,如果您不需要在它们之间进行协调,并且可以单独处理每个异步操作,那么您不需要Promise.all()。您可以使用自己的.then()处理程序触发每个单独的异步操作,并且不需要它们之间的协调。

此外,Promise.all()具有所谓的“快速失败”实现。它返回一个主承诺,一旦您传递的第一个承诺拒绝,它将拒绝,或者当所有承诺都已解决时它将解决。因此,使用Promise.all()这种类型的实现需要适合您的情况。在其他情况下,您希望运行多个异步操作,并且需要所有结果,即使其中一些失败也是如此。 Promise.all()不会直接为您做到这一点。相反,您可能会使用Promise.settle()这样的情况。您可以看到an implementation of .settle() here,即使某些结果失败,也可以访问所有结果。当您希望某些操作可能失败并且您有一个有用的任务来处理来自任何操作成功的结果或者您想要检查所有未能根据该操作做出决策的操作的失败原因时,这尤其有用。 p>

  

是否有使用promise.all()的最佳做法?应该是吗?   理想情况下,仅当所有promise对象都相同或者使用时才使用   类似的类型?

如上所述,单个异步操作是什么或它们是否是相同类型并不重要。只有你的代码需要协调它们并知道它们何时都成功才有意义。

当您使用Promise.all()时列出一些情况也很有用:

  1. 当您只有一个异步操作时。只需一个操作,您就可以在一个承诺上使用.then()处理程序,而Promise.all()没有理由。
  2. 当您不需要在多个异步操作之间进行协调时。
  3. 当快速失败实施不合适时。如果您需要所有结果,即使某些结果失败,那么Promise.all()也不会自行完成。你可能会想要Promise.settle()之类的东西。
  4. 如果您的异步操作并未全部返回承诺,Promise.all()将无法跟踪未通过承诺管理的异步操作。

答案 1 :(得分:2)

很难回答这些问题,因为当他们使用语言功能的可用API时,他们倾向于回答这些问题。基本上,只要你避免使用anti-patterns,就可以以任何适合你用例的方式使用Promise。

  

使用promise.all()

的正确方案是什么

任何操作取决于多个承诺的成功解决的情况。

  

是否有使用promise.all()的最佳做法?理想情况下,只有在所有promise对象具有相同或相似类型的情况下才能使用它吗?

一般来说,不,不。

答案 2 :(得分:2)

当我必须对我的API做一些请求时我使用promise.all()并且我不希望在应用程序加载所有请求的数据之前显示某些东西,所以我延迟执行流程直到我拥有所有数据我需要。

示例:

我想做什么我想加载我的应用及其产品的用户(想象您必须做多个请求),然后在我的应用中使用用户的电子邮件和每个用户的产品名称。

我接下来做什么我将请求发送到我的API创建承诺并使用promise.all()

加载所有数据后的操作一旦数据到达我的应用,我就可以执行promises.all()的回调,然后让用户看到该表。< / p>

我希望它可以帮助您了解使用promises.all()

的情况

答案 3 :(得分:2)

Promise.all用于等待多个Promise并行解析(同时)。它返回一个Promise,它在所有输入Promise已解析时解析:

// p1, p2, p3 are Promises
Promise.all([p1, p2, p3])
  .then(([p1Result, p2Result, p3Result]) => {
    // This function is called when p1, p2 and p3 have all resolved.
    // The arguments are the resolved values.
  })

如果输入Promise的任何被拒绝,Promise.all返回的Promise也会被拒绝。

常见的情况是等待几个API请求完成,以便您可以合并其结果:

 const contentPromise = requestUser();
 const commentsPromise = requestComments();

 const combinedContent = Promise.all([contentPromise, commentsPromise])
   .then(([content, comments]) => {
     // content and comments have both finished loading.
   })

您可以将Promise.allPromise实例一起使用。

答案 4 :(得分:0)

Promise.all-当你想要等待多个promise完成时,或者Promise.all(iterable)方法返回一个promise,当迭代参数中的所有promise都已解析时,该方法很有用。或拒绝与第一次通过的拒绝承诺的原因。

2.只需使用Promise.all(files).catch(err =&gt; {}) 如果任何承诺被拒绝,这将引发错误。

3.如果你想等待所有的话,请使用.ref。对所有的承诺.all 承诺拒绝或履行

  1. 语法-Promise.all(iterable);

答案 5 :(得分:0)

我倾向于使用promise for all:

myService.getUsers()
   .then(users => {
       this.users = users;

       var profileRequests = users.map(user => {
           return myService.getProfile(user.Id); // returns a promise
       });

       return Promise.all(profileRequests);
   })
   .then(userProfilesRequest => {
       // do something here with all the user profiles, like assign them back to the users.

       this.users.forEach((user, index) => {
           user.profile = userProfilesRequest[index];
       });
   });

在这里,我们为每个用户提供了他们的个人资料。我不希望我的承诺链失控,因为我有x许多承诺要解决。

所以Promise.all()基本上会将我的所有承诺汇总回来,我可以通过下一个then来管理。我可以继续这样做,只要像我喜欢的每个配置文件,我想得到相关的设置等等。每次我创造更多的承诺,我可以将它们全部汇总成一个。

答案 6 :(得分:0)

Promise.all传递来自传递的可迭代对象中所有promise的值数组。

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

var isCallFailed = false;
function myEndpoint1() {
  return isCallFailed ? Promise.reject("Bohoo!") :Promise.resolve({"a":"a"});
}
function myEndpoint2() {
  return Promise.resolve({"b":"b"});
}

Promise.all([myEndpoint1(), myEndpoint2()])
.then(values => {
  var data1 = values[0];
  var data2 = values[1];
  alert("SUCCESS... data1: " + JSON.stringify(data1) + "; data2: " +  JSON.stringify(data2));
})
.catch(error => {
  alert("ERROR... " + error);
});

您可以通过制作isCallFailed = true来尝试其他案例。

答案 7 :(得分:0)

正如@joews所提到的,可能应该明确指出的Promise.all的重要特征之一是,它使您的异步代码更快更高效。

这使得它非常适合包含独立调用的代码(我们希望在代码其余部分继续之前返回/完成),尤其是当我们进行前端调用并希望用户体验尽可能平稳时。

async function waitSecond() {
  return new Promise((res, rej) => {
    setTimeout(res, 1000);
  });
}

function runSeries() {
  console.time('series');
  waitSecond().then(() => {
    waitSecond().then(() => {
      waitSecond().then(() => {
        console.timeEnd('series');
      });
    });
  });
}

function runParallel() {
  console.time('parallel');
  Promise.all([
    waitSecond(),
    waitSecond(),
    waitSecond(),
  ]).then(() => {
    console.timeEnd('parallel');
  });
}

runSeries();
runParallel();

答案 8 :(得分:-2)

如果您只对Promise.all感兴趣,请阅读以下Promise.all

Promise(通常称为“Promise”) - 提供组织异步代码的便捷方式。

承诺 - 是一个包含你的州的特殊对象。最初,等待(“等待”),然后 - 其中一个:履行(“成功”)或拒绝(“完成错误”)。

关于挂起回调的承诺可以有两种类型:

  • unFulfilled - 当承诺处于“完成状态”时触发 成功。“
  • 拒绝 - 在“犯错”中的承诺时触发。

创建承诺的语法:

var promise = new Promise(function(resolve, reject) {
  // This function will be called automatically

  // It is possible to make any asynchronous operations,
  // And when they will end - you need to call one of:
  // resolve(result) on success
  // reject(error) on error
})

悬挂处理程序的通用方法:

promise.then(onFulfilled, onRejected)
  • onFulfilled - 将使用结果调用的函数 解决。

  • onRejected - 错误拒绝时将调用的函数。

在它的帮助下,您可以分配处理程序一次,只分配一个:

// onFulfilled It works on success
promise.then(onFulfilled)
// onRejected It works on error
promise.then(null, onRejected)

同步投掷 - 与拒绝

相同
'use strict';

let p = new Promise((resolve, reject) => {
  // то же что reject(new Error("o_O"))
  throw new Error("o_O");
});

p.catch(alert); // Error: o_O

<强> Promisification Promisification - 在获取异步功能并使其成为返回PROMIS的包装器时。

在Promisification之后,功能使用通常变得更加方便。

例如,创建一个使用XMLHttpRequest请求的包装器

httpGet函数(url)将返回PROMIS,在使用url成功加载数据后,将使用这些数据来实现,并且在出现错误的情况下 - 被拒绝并显示错误信息:

function httpGet(url) {

    return new Promise(function(resolve, reject) {

        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);

        xhr.onload = function() {
            if (this.status == 200) {
                resolve(this.response);
            } else {
                var error = new Error(this.statusText);
                error.code = this.status;
                reject(error);
            }
        };

        xhr.onerror = function() {
            reject(new Error("Network Error"));
        };

        xhr.send();
    });

}

如您所见,函数XMLHttpRequest对象内部像往常一样创建并发送,分别在调用onload / onerror时,解析(在状态200)或拒绝。

使用:

httpGet("/article/promise/user.json")
    .then(
        response => alert(`Fulfilled: ${response}`),
        error => alert(`Rejected: ${error}`)
    );

并行执行

如果我们想同时实现多个异步进程并处理结果会怎样?

Promise类具有以下静态方法。

<强> Promise.all(迭代)

调用Promise.all(iterable)接收一个数组(或其他可迭代对象)并返回PROMIS PROMIS,它等待所有传输的PROMIS完成,然后用一系列结果更改为“done”状态。

例如:

Promise.all([
    httpGet('/article/promise/user.json'),
    httpGet('/article/promise/guest.json')
]).then(results => {
    alert(results);
});

假设我们有一个URL数组。

let urls = [
  '/article/promise/user.json',
  '/article/promise/guest.json'
];

要同时下载它们,您需要:

  1. 为与PROMIS对应的每个网址创建。
  2. 在Promise.all中包装一系列PROMIS。
  3. 我们得到了这个:

    'use strict';

    let urls = [
      '/article/promise/user.json',
      '/article/promise/guest.json'
    ];
    
    Promise.all( urls.map(httpGet) )
      .then(results => {
        alert(results);
    });
    

    请注意,如果任何Promise以错误结束,结果将

    Promise.all这个错误。

    与此同时PROMIS的其余部分被忽略了。

    例如:

    Promise.all([
        httpGet('/article/promise/user.json'),
        httpGet('/article/promise/guest.json'),
        httpGet('/article/promise/no-such-page.json') // (нет такой страницы)
    ]).then(
        result => alert("не сработает"),
        error => alert("Ошибка: " + error.message) // Ошибка: Not Found
    )
    

    总计:

    • Promise - 是一个特殊的对象,用于存储其状态,即当前状态 结果(如果有的话)和回调。
    • 当您创建新的Promise((resolve,reject)=&gt; ...)函数时 参数自动启动,应该调用resolve(result) 成功,拒绝(错误) - 错误。
    • 参数解析/拒绝(仅限第一个,其余部分被忽略) 传递给这个承诺的处理程序。
    • 处理程序是通过调用.then / catch。
    • 指定的
    • 使用Channing将结果从一个处理器传输到另一个处理器。

    https://www.promisejs.org/patterns/