7
async function getContent(){
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    const content =  await page.content();
    await console.log(content);
    await browser.close();
}

setInterval(searchTarget(), 13000);

I have this async function that gets content from a webpage using puppeteer. I want to be able to check the web page every so often, so I tried to use setinterval but I kept getting errors. Any ideas?

4
  • 2
    "I kept getting errors" - what errors? Commented Jan 1, 2021 at 7:15
  • 1
    My advice: Don't use setInterval. Call the function again in the resolve with a timeout Commented Jan 1, 2021 at 7:15
  • 1
    You've posted a function called getContent but you're passing the result of a function-call (not the function itself) named searchTarget to setInterval. Commented Jan 1, 2021 at 7:16
  • 1
    Also you need to not have () in an interval or timeout call setInterval(searchTarget, 13000); Commented Jan 1, 2021 at 7:17

2 Answers 2

7
  • You've posted the definition of getContent, not searchTarget.
  • You're passing the result of searchTarget to setInterval rather than passing a reference to the function searchTarget.
  • You say you're getting errors but haven't said what those errors are.
  • You can use an async function with setInterval.
  • You don't need to use await with console.log (you shouldn't use await because as console.log doesn't return anything, let alone a Promise<T>).

I assume what you actually want is this:

async function getContent() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    const content =  await page.content();
    console.log(content);
    await browser.close();
}

const timerId = window.setInterval( getContent, 13 * 1000 );

// You can call `window.clearInterval( timerId )` to stop the interval loop.

I recommend adding error-handling that stops the interval loop on the first error:

/** @type {number} */
let intervalTimerId = null;

async function getContent() {
    try {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(url);
        const content =  await page.content();
        await console.log(content);
        await browser.close();
    }
    catch( err ) {
        console.error( "Error in getContent: %o", err );
        if( intervalTimerId ) {
            window.clearInterval( intervalTimerId );
        }
    }
}

intervalTimerId = window.setInterval( getContent, 13 * 1000 );

Alternative approach:

As other users like @mplungjan and @RohanAsokan have pointed out, there are potential design issues with your code because setInterval will call getContent every 13 seconds even if the previous call to getContent still hasn't finished yet - this could happen if (for example) await page.content() took longer than 13 seconds to run.

In which case the solution is to use window.setTimeout instead of window.setInterval and to call it from within getContent, like so:

/** @type {number} */
let lastSetTimeoutId = null;

async function getContentAndStartLoop() {
    try {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(url);
        const content =  await page.content();
        console.log(content);
        await browser.close();

        lastSetTimeoutId = window.setTimeout( getContentAndStartLoop, 13 * 1000 );
    }
    catch( err ) {
        console.error( "Error in getContent: %o", err );
    }
}

Note that getContentAndStartLoop will resolve after the first loop but keep on running itself until an error is thrown.

Better approach:

I think it'd be better to structure it like so (using a Promise-adapter for setTimeout named delay):

async function myProgram() {
    
    const url     = "https://thispersondoesnotexist.com/":
    const browser = await puppeteer.launch();
    const page    = await browser.newPage();
    
    try {
        while( true ) {
        
            await page.goto( url );
        
            const content = await page.content();
            console.log( content );

            await delay( 13 * 1000 );
        }
    }
    catch( err ) {
        console.error( "Error in myProgram: %o", err );
    }
    finally {
        await browser.close();
    }
    
}

async function delay( ms, state = null ) {
    
    return new Promise( ( resolve, reject ) => {
        window.setTimeout( () => resolve( state ), ms );
    } );
}
Sign up to request clarification or add additional context in comments.

Comments

3

I will ask you a question and you will have your answer.

What do you think will happen if the async request to getContent() takes more time than the 13000 millisecond interval?

Hence a better option would be to resolve the promise and call the function again as suggested by @mplungjan in the comments.

A possible but unclean solution would be to clear the interval if a previous promise has not been resolved.

7 Comments

how would i go about resolving the promise and calling the function? ( I am veeeery new to promises)
@b0b75 You don't need to manually "resolve" any promises - that's handled for you by the await operator. See my updated answer for an example.
@Dai I can't comment on your post. But just to point out, by repeatedly calling the function and setting it in a infinite call stack, you are loosing out on the optimization advantages given by setInterval. @b0b75 also look into this.
@RohanAsokan "by repeatedly calling the function and setting it in a infinite call stack" - please explain what you mean by this. I don't believe there is a potential for a stack-overflow in the code I posted. If there's a problem with my code please post a comment reply to my answer with more details.
@rohanAsokan Neither does setTimeout nor the use of Promise. Anyway, worrying about the stack-size in JS is almost entirely unnecessary - either your code causes an infinite recursion and stack-overflow or it doesn’t. Remember that because JS doesn’t have explicit stack allocation (unlike C) the only way a non-buggy script would overflow was if the data structure it was traversing was ridiculously huge; which won’t happen in practice (because if it was that big you wouldn’t be using JS in the first place)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.