这更像是一个概念性问题。我理解Promise设计模式,但无法找到可靠的来源来回答我关于promise.all()
的问题:
promise.all()
OR
promise.all()
的最佳做法?理想情况下,只有当所有的promise对象都是相同或相似类型时才能使用它吗?我唯一能想到的是:
promise.all()
,如果有人拒绝,则使用拒绝。答案 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()
时列出一些情况也很有用:
.then()
处理程序,而Promise.all()
没有理由。Promise.all()
也不会自行完成。你可能会想要Promise.settle()
之类的东西。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.all
与Promise
实例一起使用。
答案 4 :(得分:0)
Promise.all-当你想要等待多个promise完成时,或者Promise.all(iterable)方法返回一个promise,当迭代参数中的所有promise都已解析时,该方法很有用。或拒绝与第一次通过的拒绝承诺的原因。
2.只需使用Promise.all(files).catch(err =&gt; {}) 如果任何承诺被拒绝,这将引发错误。
3.如果你想等待所有的话,请使用.ref。对所有的承诺.all 承诺拒绝或履行
答案 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”) - 提供组织异步代码的便捷方式。
承诺 - 是一个包含你的州的特殊对象。最初,等待(“等待”),然后 - 其中一个:履行(“成功”)或拒绝(“完成错误”)。
关于挂起回调的承诺可以有两种类型:
创建承诺的语法:
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'
];
要同时下载它们,您需要:
我们得到了这个:
'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
)
总计: