In my project (VUE Vuex) I need to make some API requests simultaneously, according to some contents
and then process the results.
The getters.api_props(key)
function will return the method ('post', 'patch', 'delete') or false if there is no need for a request. It will also return the url and the object that is needed for the request.
The api
method returns the request as a Promise using axios.
Here is my code so far:
var contents = {person: {...}, info: {...}}
var promiseArray = [];
for (var key in contents) {
let [method, url, hash] = getters.api_props(key);
if (method) { promiseArray.push(api[method](url, hash)) }
}
await Promise.allSettled(promiseArray).then((results) => {
results.map(r => {
// THE RESULTS WILL BE PROCESSED HERE like:
// commit("save", [key, r])
console.info(r)
})
}).catch(e => console.log('ERROR:::',e)).finally(commit("backup"))
The problem is that the results does not include the 'key' so the save
method that is called cannot know where to save the results.
Can you propose a fix or a better solution?
CodePudding user response:
So, to answer my own question, after Bergi's comments I filled promiseArray
with
api[method](url, hash).then((r) => [key, r]).catch((e) => {throw [key, e.response]})
and then found the key that I needed:
await Promise.allSettled(promiseArray).then((results) => {
results.map((r) => {
if (r.status=='fulfilled') {
console.info(r.value[0],':',r.value[1].data)
}
if (r.status=='rejected') {
console.warn(r.reason[0],':',r.reason[1])
}
})
})
CodePudding user response:
I would recommend to write
const contents = {person: {...}, info: {...}}
cosnt promiseArray = [];
for (const key in contents) {
let [method, url, hash] = getters.api_props(key);
if (method) {
promiseArray.push(api[method](url, hash)).then(value => ({
key,
status: 'fulfilled',
value
}), reason => ({
key,
status: 'rejected',
reason
})))
}
}
const results = await Promise.all(promiseArray);
for (const r of results) {
if (r.status=='fulfilled') {
console.info(r.key, ':', r.value.data)
commit("save", [r.key, r.value]);
} else if (r.status=='rejected') {
console.warn(r.key, ':', r.reason)
}
})
commit("backup");
CodePudding user response:
You obviously don't need to take this, but I fiddled with it for a while and this is what I liked best:
import forEach from 'lodash/forEach'
import mapValues from 'lodash/mapValues'
import { api, getters } from 'somewhere'
var contents = {person: {...}, info: {...}}
const promiseContents = mapValues(contents, (value, key) => {
let [method, url, hash] = getters.api_props(key);
if (!method) { return }
return api[method](url, hash)
})
await Promise.allSettled(Object.values(promiseContents))
forEach(promiseContents, (promise, key) => {
promise.then(response => {
if (promise.status === 'rejected') {
console.warn(key, ':', response)
}
console.info(key, ':', value.data)
})
})
The big requirement is that you include lodash in the project, but that is not an unusual ask in javascript projects.
mapValues allows you to keep the structure of your contents
object while replacing the values with promises. I just use await on Promise.allSettled
to tell the rest of the code when it can go. I just ignore the results.
Finally, using lodash's forEach I interpret the results. The advantage here is that every promise is run in a function alongside the key from your original contents
object.
I like doing it this way because it doesn't require you to create a [key, result] array. That said, either way works fine.