Javascript: Promise.all doesn't seem to be resolving [duplicate] - javascript

This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 7 years ago.
I'm trying to map over some RSS feeds using feedparser-promised, but my call to Promise.all() isn't returning anything. (use of var is from my REPL, which doesn't support const or let)
var feedparser = require('feedparser-promised');
var R = require('ramda');
var URLS = ['http://feeds.gawker.com/gizmodo/full',
'http://kotaku.com/vip.xml',
'http://www.medievalhistories.com/feed/'];
var getAllFeeds = (urls) => {
promises = R.map(feedparser.parse, urls);
Promise.all(promises)
.then((itemArrs) => itemArrs)
.catch((err) => {throw new Error(err)});
}
var x = getAllFeeds(URLS);
console.log(x);
x comes back as undefined. If I do a log on promises, it shows as an array of Promises, as expected. What am I missing?

x is undefined because getAllFeeds is a arrow function with statement body that does not explicitly return.
You should return the Promise.all promise and consume the results in then/catch handlers:
var getAllFeeds = (urls) => {
var promises = R.map(feedparser.parse, urls);
return Promise.all(promises)
}
getAllFeeds(URLS)
.then(items => {
console.log(items);
})
.catch(err => {
console.error(err);
})

Related

fetch constantly returns Promise {<pending>} [duplicate]

This question already has answers here:
How can I access the value of a promise?
(14 answers)
Async function returning promise, instead of value
(3 answers)
Closed 9 months ago.
I decided to create a special service aka ES6 class with needed functions to get data from API and then in index.js I could create an instance of the class and work with it. Unfortunately, when I try it, it always returns
Promise {<pending>}
and I don't really know what to do.
nytService.js:
export default class NYTService {
urlBase = "https://api.nytimes.com/svc/topstories/v2/";
category = "world";
apikey = *my api key* ;
async getNews(category = this.category) {
let url = `${this.urlBase}${category}.json?api-key=${this.apikey}`;
let res = await fetch(url)
let data = await res.json();
return data;
}
}
index.js:
import NYTService from "../services/nytService.js";
let nytService = new NYTService();
async function getNewsFinally() {
let res = await nytService.getNews();
return res;
}
console.log(getNewsFinally());
I did tried different things with the getNewsFinally function, did various .then chains, nothing helped
See if this tells you why:
async getNews(category = this.category) {
let url = `${this.urlBase}${category}.json?api-key=${this.apikey}`;
try {
let res = await fetch(url)
if (!res.ok) {
return res.statusText;
}
return await res.json();
} catch(err) {
console.error(err);
throw new Error(err);
}
}

async/await in forEach loop [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
The below JavaScript is returning a strange version of an array. The below forEach logs nothing to console. I'm probably missing something quite fundamental here, but I know for a fact that the array is populated...unless it's not populated until later due to being async and Chrome just evaluates the console.log after the fact?
let damageRollStringArr = []
monster.damage_types.forEach(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
damageRollStringArr.forEach(el => console.log(el))
// Was returning an empty array[] with objects inside?
return damageRollStringArr
Thanks
demageRollStringArr.forEach (2nd foreach) wont wait for monster.demage_types.forEach (1st foreach) to execute although there is async await in the first forEach
To achieve what you want to do, try this,
let damageRollStringArr = []
const promises = monster.damage_types.map(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
await Promise.all(promises)
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
Or, you can use normal for() loop to replace 1st foreach
let damageRollStringArr = []
for(let i = 0; i < monster.demage_types.length; i++) {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
}
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
1st solution will run the loop parallel,
2nd solution will run the loop sequential

What is the difference b/w the two async/await functions? [duplicate]

This question already has answers here:
Difference between `return await promise` and `return promise`
(7 answers)
Closed 5 years ago.
const displaySymbols = async (symbols) => {
const sym = await Promise.all(symbols.map(s => {
// createEl return a promise
return createEl(s)
}))
return sym
}
const displaySymbols = async (symbols) => {
const sym = await Promise.all(symbols.map(async s => {
return await createEl(s)
}))
return sym
}
The results are same, without Promise.all, sym would be always a promise array, no matter createEl is await-ed or not, then is it necessary to use async function as map method?
P.S. The code is just a demo.
The second one is superflous. Its like:
Promise.resolve( new Promise() )

Promise.all returns function [duplicate]

This question already has answers here:
Returning function and invoking with Promise.all
(2 answers)
Closed last month.
I would like use Async/Await with fetch API. So, i've 2 async function for return result.json().
I add my 2 Promise in Promise.all([]), but the values returned is 'function()'.
My code :
// Load external users
const externalUsers = async () => {
const result = await fetch(url);
return result.json();
};
const localUsers = async () => {
const result = await Users.allDocs({ include_docs: true });
return result.rows;
};
Promise.all([externalUsers, localUsers]).then(values => {
console.log(values); // return (2) [function, function]
});
I don't understand why. Can you help me ?
Thank you community !
Run your functions in the Promise.all. So they will return Promises which will be settled and passed to the then function.
Promise.all([externalUsers(), localUsers()]).then(values => {
console.log(values);
});
You should await your Promise.all
const values = await Promise.all([...]);
const value1 = values[0];
...
The reason you are seeing functions, is because Promise.all returns a Promise that resolves to an array. So by awaiting the Promise.all, you wait for them all to finish/resolve first.
You can also do,
const [externalUsersResult, localUsersResult] = await Promise.all([externalUsers, localUsers])

Passing intermediate data between promises in JS without using Promise.all and Promise.resolve [duplicate]

This question already has answers here:
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 5 years ago.
I'm kind of a JS noob, but so far I really like the ES6 / React / Immutable capability to do functional programming and FRP, and in particular, the promise api. I particularly like the pattern of chaining .then's, eg, somePromiseGenerator().then(...).then(...).catch(...). This is perfect when the flow of asynchronous calls is perfectly linear. However, Often I want to pass results from the top of this chain to the end.
The sub-optimal pattern I've been using looks like:
somePromiseGenrator()
.then(r => {
const inter = makeSomeIntermediateResults(r);
const newPromise = makeNewPromise(r);
return Promise.all([newPromise, Promise.resolve(inter)]);
})
.then(r => {
handleR0andR1(r[0], r[1]);
})
this happens, for instance, when i get data from ElasticSearch and want to supplement it with stuff that's in SQL or Neo4J or call out to a secondary API.
Using Promise.all and especially Promise.resolve seems like a waste of effort. Is there a better way to do this work?
Using array destructuring to name variables:
somePromiseGenrator()
.then(r => {
const inter = makeSomeIntermediateResults(r);
const newPromise = makeNewPromise(r);
return Promise.all([newPromise, inter]);
})
.then([newPromiseResult, intermediateResult]) => {
handleR0andR1(newPromiseResult, intermediateResult);
})
That alone is much clearer to follow, and I also removed the redundant Promise.resolve(), as non-promise values in the array passed to Promise.all() will automatically be wrapped in that already.
Using async / await:
Assuming your version of Node.js is >= 7.6 (or you're using a transpiler / bundler / polyfill that supports ES2016 features), you can convert the following:
function promiseChain() {
return somePromiseGenrator()
.then(r => {
const inter = makeSomeIntermediateResults(r);
const newPromise = makeNewPromise(r);
return Promise.all([newPromise, inter]);
})
.then([newPromiseResult, intermediateResult]) => {
return handleR0andR1(newPromiseResult, intermediateResult);
})
}
into this:
async function promiseChain() {
const r = await somePromiseGenerator();
// I'm assuming this isn't a promise
// since it was initially wrapped in Promise.resolve()
const inter = makeSomeIntermediateResults(r);
const newPromiseResult = await makeNewPromise(r);
return handleR0andR1(newPromiseResult, inter);
}
You could define inter as a variable that has an extended scope, e.g. make it a parameter in an immediately invoked function expression:
(inter => somePromiseGenerator()
.then(r => {
inter = makeSomeIntermediateResults(r);
return makeNewPromise(r);
})
.then(r => handleR0andR1(r, inter))
)();
See also the options offered in this accepted answer, of which mine is a variant on option 2.
I guess you can do something like this if you don't prefer using Promise.all:
function pack(){
var args = arguments;
if((args.length - 1) % 2 != 0){
throw "Invalid input";
}
var obj = args[0],
promises = [];
for(var i = 1; i < args.length; i+=2){
let promise = args[i],
name = args[i+1];
promises.push(promise.then(val => {
obj[name] = val;
}));
}
return Promise.all(promises).then(() => obj);
}
Then you can use it this way:
Promise
.resolve({})
.then(obj => {
return pack(obj, genVal("a"), "a", genVal("b"), "b");
})
.then(obj => {
return pack(obj, genVal("c"), "c");
})
.then(console.log);
/* {
partA: "some value from part A",
partB: "some value from part B",
partC: "some value from part C"
} */
https://jsfiddle.net/DerekL/ssr23mjy/

Categories