Younes Yaas
Younes Yaas

Reputation: 498

Puppeteer - ExpressJS infinite loop a function

I have a problem with my Express JS app : When I'm trying to call a function, this function is endlessly called ... It opens a lot of chromium browser and cause performance issues ...

I just want to call this function one time.

I've found a solution to make it work (And called just one time), but in this situation I can't pass any parameters ...

const farm = (async () => {
    const browser = await puppeteer.launch({headless: true});
    const page = await browser.newPage();
    await page.goto("https://www.example.com/?s=" + term);
    await page.waitForSelector("div");
    const postLinks = await page.evaluate(() => {
        let postLinks = [];
        let elements = document.querySelectorAll('div.article');
        for (element of elements) {
            postLinks.push({
                title: element.querySelector('div.meta-info > h3 > a')?.textContent,
                url: element.querySelector('div.meta-info > h3 > a')?.href
            })
        }
        return postLinks;
    });
    console.log(postLinks);
    await browser.close();
})();

app.get('/', (req, res) => {
    var term = "Drake";
    res.send(farm);
});

With the code below, I can pass parameters but I can't return the result in "res.send", and the function is called endlessly :

const farm = async (term) => {
    const browser = await puppeteer.launch({headless: true});
    const page = await browser.newPage();
    await page.goto("https://www.example.com/?s=" + term);
    await page.waitForSelector("div");
    const postLinks = await page.evaluate(() => {
        let postLinks = [];
        let elements = document.querySelectorAll('div.article');
        for (element of elements) {
            postLinks.push({
                title: element.querySelector('div.meta-info > h3 > a')?.textContent,
                url: element.querySelector('div.meta-info > h3 > a')?.href
            })
        }
        return postLinks;
    });
    console.log(postLinks);
    await browser.close();
  }

app.get('/', (req, res) => {
    var term = "Drake";
    var results = farm(term);
    res.send(results);
});

Did I miss something ?

Thanks !

Upvotes: 1

Views: 208

Answers (1)

traynor
traynor

Reputation: 8622

It's not an infinite loop, but unresolved promise. The farm returns a promise, which you're not waiting for, but instead send the pending promise before it resolves, i.e. before the puppeteer is done.

You need to wait for farm's promise to resolve, make middleware function async and add await to the farm call:

app.get('/', async(req, res) => {
    var term = "Drake";
    // farm returns a promise, so you need to wait for it to resolve, i.e. block execution
    // otherwise it just sends pending promise, because node.js runs in non-blocking fashion
    var results = await farm(term);
    res.send(results);
});

Upvotes: 2

Related Questions