0

I am running this function with NodeJS, but the process never stops running, despite the fact that I am returning a value once all promises have been resolved.

How can I modify this code so the function terminates when it's done?

let Parser = require('rss-parser');
let parser = new Parser();

var sources = {
    feed1: 'http://www.example.url/feed',
    feed2: 'http://www.another.url/feed'
}

(async() => {
    var promises = [];
    for (var feedName in sources) {
        if (sources.hasOwnProperty(feedName)) {
            const result = parser.parseURL(sources[feedName])
            promises.push(result)   
        }
    }
    return await Promise.all(promises)
})()
nemesis
  • 53
  • 1
  • 1
  • 10

2 Answers2

0

You can take a simple approach handling promises in one array to catch them after parsing each url. Something like this:

let Parser = require('rss-parser');
let parser = new Parser();

var sources = {
    feed1: 'http://www.example.url/feed',
    feed2: 'http://www.another.url/feed'
}

function parsePromise(url) {
    return new Promise((resolve,reject) => {
        let data = parser.parseURL(url);
        resolve(data);  
    });
}

// main
toread = [];
for (var feedName in sources) {
    let url = sources[feedName];
    let p = parsePromise(url);
    toread.push(p);
}

Promise.all(toread).then((data) => {
    console.log(data);
});
cardeol
  • 2,218
  • 17
  • 25
  • 1
    Thank you, but I want to run every request in parallel to reduce the run-time. The missing semicolon was actually the only issue in the code above. – nemesis Feb 07 '18 at 14:38
  • My code runs all the requests in parallel and then are merged into Promise.all – cardeol Feb 07 '18 at 16:22
  • Of course, I see that now, you are not waiting for each promise to resolve before starting the next one. – nemesis Feb 08 '18 at 20:17
0

First, I think your async arrow function is incorrect. You are not actually invoking it properly. See the syntax for async arrow functions in this question: Syntax for async arrow function.

Since you are already trying to do an immediate anonymous function, just use the function declaration instead of arrows.

Additionally, you are trying to return something from an anonymous, immediately invoked function and you aren't doing anything with the returned value.

Not only that, but you are awaiting the Promise.all() only to have whatever you waited on get wrapped in a Promise anyway since async functions return Promises no matter what.

Second, use more map()s or intermediate values so you program flows more clearly. The benefit of await is that you can write what looks like synchronous code, but it will be handled in an asynchronous manner.

const Parser = require("rss-parser"),
    parser = new Parser();

const sources = {
    feed1: "https://sports.yahoo.com/nhl/teams/bos/rss.xml",
    feed2: "https://sports.yahoo.com/nhl/teams/buf/rss.xml"
};

(async function () {
    let data
    try {
        const sourcesArr = Object.keys(sources).map(k => sources[k]),
            feedPromises = sourcesArr.map(source => parser.parseURL(source));

        data = await Promise.all(feedPromises);
    } catch (err) {
        console.error(err);
    }

    console.log(data);
}());
zero298
  • 25,467
  • 10
  • 75
  • 100
  • Other than changing `return` to `console.log()`, and adding a `try`/`catch` that (probably) isn't going to catch anything here, you haven't changed the control flow at all. The asynchronous IIAFE _was_ written correctly, it was just that ASI failed to insert a semicolon after the `const sources = ...` statement, and while then `return` value wasn't being used, the OP was probably already aware of that. – Patrick Roberts Feb 06 '18 at 16:56
  • You can also reduce your "more clearly flowing program" to `const feedPromises = Object.values(sources).map(source => parser.parseURL(source))` – Patrick Roberts Feb 06 '18 at 17:00