是否可以将 axios.all 与 then() 一起用于每个承诺?
Is it possible to use axios.all with a then() for each promise?
我有一个 React 组件触发一个事件来获取数据。这导致动态数量的存储过程调用来获取数据,并且来自每个调用的数据存储在完全不同的位置。然后我需要在接收到所有数据并可用后重新渲染。我在 axios 中使用 promises。
由于 axios 调用的数量是动态的,我正在构建一个数组并将其插入到 axios.all
中,如下所示:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(axios.get(request[i].url, { params: {...} }));
}
axios.all(promises).then(/* use the data */);
问题是每个 axios 请求 returns 数据被添加到一个完全不同的地方的对象。由于我无法将它们全部放在一个 then
中的正确位置(我怎么知道哪个响应在哪个位置?),我尝试这样做:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(
axios.get(request[i].url, { params: {...} })
.then(response => {myObject[request[i].saveLocation] = response.data;})
);
}
axios.all(promises).then(/* use the data */);
但是,这并不像我预期的那样有效。每个 get
之后的 then
被执行,但直到 then
附加到 axios.all
之后才执行。显然这是一个问题,因为我的代码试图在数据保存到对象之前使用它。
有没有办法为每个 axios.get
单独调用 axios.get
,在其相应的 promise 被解析后执行,然后有一个最终的 then
仅在 所有 的 promise 被解决后执行,现在对象已被填充后使用数据?
如果您第二次尝试的行为确实如此,则表明 axios
不符合 Promise/A+ 标准。 then
回调的 return 值必须是 then
所承诺 return 实现的值。由于这是您推入数组的承诺,因此 axios.all
将 return 用于该承诺的值只能通过首先执行 then
回调来获知。
即使您没有在 then
回调中明确 return 一个值,这也不会影响上述规则:在这种情况下 return 值是 undefined
,一旦相应的承诺得到解决, 应该由 axios.all
提供的值。
具体参见规则 2.2.7、2.2.7.1、2.3.2.1、2.3.2.2 in the specs of Promise/A+:
2.2.7 then
must return a promise.
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 If either onFulfilled
or onRejected
returns a value x
, run the Promise Resolution Procedure [[Resolve]](promise2, x)
.
[...]
To run [[Resolve]](promise, x)
, perform the following steps:
[...]
2.3.2 If x
is a promise, adopt its state:
2.3.2.1 If x
is pending, promise
must remain pending until x
is fulfilled or rejected.
2.3.2.2 If/when x
is fulfilled, fulfill promise
with the same value.
所以我建议改用 Promise/A+ 兼容的承诺实现。还有其他几个库,例如 request-promise.
或者,您可以使用本机 ES6 Promise 实现, 您自己。
ES6 提供 Promise.all
保证以与提供承诺相同的顺序提供已解析的值。
好的,所以我找到了一种方法来完成我需要的事情,而无需在每个 get
上使用 then
。由于传递给 axios.get
的参数包含足够的信息来确定保存位置,并且由于我可以从响应中读回参数,所以我可以执行以下操作:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(axios.get(request[i].url, { params: {...} }));
}
axios.all(promises)
.then(axios.spread((...args) => {
for (let i = 0; i < args.length; i++) {
myObject[args[i].config.params.saveLocation] = args[i].data;
}
}))
.then(/* use the data */);
这可确保在使用对象之前接收到所有数据并将其保存到对象中。
如果您将 promise 传递给您的数组并附有各自的 then
函数
,您的初始代码可以正常工作
let promises = []; // array to hold all requests promises with their then
for (let i = 0; i < requests.length; i++) {
// adding every request to the array
promises.push(
axios.get(request[i].url, { params: { ...} })
.then(response => { myObject[request[i].saveLocation] = response.data; })
);
}
// Resolving requests with their callbacks before procedding to the last then callback
axios.all(promises).then(/* use the data */);
看来在这 post 天,axios 建议使用 Promise.all 而不是 axios.all
https://github.com/axios/axios
这对我有用,使用 Nuxtjs
async nuxtServerInit(vuexContext, context) {
console.log(context);
const primaryMenuData = {
query: `query GET_MENU($id: ID!) {
menu(id: $id, idType: NAME) {
count
id
databaseId
slug
name
menuItems {
edges {
node {
url
label
target
}
}
}
}
}`,
variables: {
"id": "Primary"
}
}
const primaryMenuOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
data: primaryMenuData,
url: 'http://localhost/graphql'
};
const postsData = {
query: `query GET_POSTS($first: Int) {
posts(first: $first) {
edges {
node {
postId
title
date
excerpt
slug
author {
node {
name
}
}
featuredImage {
node {
altText
caption
sourceUrl(size: MEDIUM)
}
}
}
}
}
}`,
variables: {
"first": 15
}
}
const postsOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
data: postsData,
url: 'http://localhost/graphql'
};
try {
const [primaryMenuResponse, postsResponse] = await Promise.all([
await axios(primaryMenuOptions),
await axios(postsOptions)
])
vuexContext.commit('setPrimaryMenu', primaryMenuResponse.data.data.menu.menuItems.edges);
vuexContext.commit('setPosts', postsResponse.data.data.posts.edges);
} catch (error) {
console.error(error);
}
},
我有一个 React 组件触发一个事件来获取数据。这导致动态数量的存储过程调用来获取数据,并且来自每个调用的数据存储在完全不同的位置。然后我需要在接收到所有数据并可用后重新渲染。我在 axios 中使用 promises。
由于 axios 调用的数量是动态的,我正在构建一个数组并将其插入到 axios.all
中,如下所示:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(axios.get(request[i].url, { params: {...} }));
}
axios.all(promises).then(/* use the data */);
问题是每个 axios 请求 returns 数据被添加到一个完全不同的地方的对象。由于我无法将它们全部放在一个 then
中的正确位置(我怎么知道哪个响应在哪个位置?),我尝试这样做:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(
axios.get(request[i].url, { params: {...} })
.then(response => {myObject[request[i].saveLocation] = response.data;})
);
}
axios.all(promises).then(/* use the data */);
但是,这并不像我预期的那样有效。每个 get
之后的 then
被执行,但直到 then
附加到 axios.all
之后才执行。显然这是一个问题,因为我的代码试图在数据保存到对象之前使用它。
有没有办法为每个 axios.get
单独调用 axios.get
,在其相应的 promise 被解析后执行,然后有一个最终的 then
仅在 所有 的 promise 被解决后执行,现在对象已被填充后使用数据?
如果您第二次尝试的行为确实如此,则表明 axios
不符合 Promise/A+ 标准。 then
回调的 return 值必须是 then
所承诺 return 实现的值。由于这是您推入数组的承诺,因此 axios.all
将 return 用于该承诺的值只能通过首先执行 then
回调来获知。
即使您没有在 then
回调中明确 return 一个值,这也不会影响上述规则:在这种情况下 return 值是 undefined
,一旦相应的承诺得到解决, 应该由 axios.all
提供的值。
具体参见规则 2.2.7、2.2.7.1、2.3.2.1、2.3.2.2 in the specs of Promise/A+:
2.2.7
then
must return a promise.promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 If either
onFulfilled
oronRejected
returns a valuex
, run the Promise Resolution Procedure[[Resolve]](promise2, x)
.[...]
To run
[[Resolve]](promise, x)
, perform the following steps:[...]
2.3.2 If
x
is a promise, adopt its state:2.3.2.1 If
x
is pending,promise
must remain pending untilx
is fulfilled or rejected.2.3.2.2 If/when
x
is fulfilled, fulfillpromise
with the same value.
所以我建议改用 Promise/A+ 兼容的承诺实现。还有其他几个库,例如 request-promise.
或者,您可以使用本机 ES6 Promise 实现, 您自己。
ES6 提供 Promise.all
保证以与提供承诺相同的顺序提供已解析的值。
好的,所以我找到了一种方法来完成我需要的事情,而无需在每个 get
上使用 then
。由于传递给 axios.get
的参数包含足够的信息来确定保存位置,并且由于我可以从响应中读回参数,所以我可以执行以下操作:
let promises = [];
for (let i = 0; i < requests.length; i++) {
promises.push(axios.get(request[i].url, { params: {...} }));
}
axios.all(promises)
.then(axios.spread((...args) => {
for (let i = 0; i < args.length; i++) {
myObject[args[i].config.params.saveLocation] = args[i].data;
}
}))
.then(/* use the data */);
这可确保在使用对象之前接收到所有数据并将其保存到对象中。
如果您将 promise 传递给您的数组并附有各自的 then
函数
let promises = []; // array to hold all requests promises with their then
for (let i = 0; i < requests.length; i++) {
// adding every request to the array
promises.push(
axios.get(request[i].url, { params: { ...} })
.then(response => { myObject[request[i].saveLocation] = response.data; })
);
}
// Resolving requests with their callbacks before procedding to the last then callback
axios.all(promises).then(/* use the data */);
看来在这 post 天,axios 建议使用 Promise.all 而不是 axios.all https://github.com/axios/axios 这对我有用,使用 Nuxtjs
async nuxtServerInit(vuexContext, context) {
console.log(context);
const primaryMenuData = {
query: `query GET_MENU($id: ID!) {
menu(id: $id, idType: NAME) {
count
id
databaseId
slug
name
menuItems {
edges {
node {
url
label
target
}
}
}
}
}`,
variables: {
"id": "Primary"
}
}
const primaryMenuOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
data: primaryMenuData,
url: 'http://localhost/graphql'
};
const postsData = {
query: `query GET_POSTS($first: Int) {
posts(first: $first) {
edges {
node {
postId
title
date
excerpt
slug
author {
node {
name
}
}
featuredImage {
node {
altText
caption
sourceUrl(size: MEDIUM)
}
}
}
}
}
}`,
variables: {
"first": 15
}
}
const postsOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
data: postsData,
url: 'http://localhost/graphql'
};
try {
const [primaryMenuResponse, postsResponse] = await Promise.all([
await axios(primaryMenuOptions),
await axios(postsOptions)
])
vuexContext.commit('setPrimaryMenu', primaryMenuResponse.data.data.menu.menuItems.edges);
vuexContext.commit('setPosts', postsResponse.data.data.posts.edges);
} catch (error) {
console.error(error);
}
},