puppeteer: wait N seconds before continuing to the next line
Asked Answered
I

7

153

In puppeteer I would like to wait a defined time before going to the next line of code.

I've tried to put a setTimeout in an evaluate function but it seems to be simply ignored

console.log('before waiting');
await page.evaluate(async() => {
  setTimeout(function(){
      console.log('waiting');
  }, 4000)
});
console.log('after waiting');

This code don't wait and just write before waiting and after waiting

Do you know how to do this?

Instrumentalist answered 24/10, 2017 at 19:55 Comment(2)
await page.evaluate(async() => { setTimeout(function(){ console.log('waiting'); }, 4000);}); your code is not right , above is the rightTindall
@Tindall that code isn't right either. I suggest deletion, or posting an answer with the correct code rather than a comment.Ulloa
B
248

You can use a little promise function,

function delay(time) {
   return new Promise(function(resolve) { 
       setTimeout(resolve, time)
   });
}

Then, call it whenever you want a delay.

console.log('before waiting');
await delay(4000);
console.log('after waiting');

If you must use puppeteer use the builtin waitForTimeout function.

await page.waitForTimeout(4000)

If you still want to use page.evaluate, resolve it after 4 seconds. You are not resolving anything.

await page.evaluate(async() => {
    await new Promise(function(resolve) { 
           setTimeout(resolve, 1000)
    });
});

But I guess you can simply use the first two examples.

Birmingham answered 26/10, 2017 at 23:24 Comment(5)
are you sure this is working ? You can't use delay() inside page.evaluate() it does not belongs to its context.Damales
I am pretty sure the delay function and the page.evaluate are different examples.Birmingham
waitFor is deprecated, use waitForTimeout instead.Qadi
it's smark. But I can't figure out why "function delay(time) { return new Promise(function(resolve) { setTimeout(resolve, time) }); }" works...Hesiod
waitForTimeout is deprecated too. Best to find a better predicate to block on: waitForFunction, waitForNetworkIdle, waitForResponse, waitForSelector, etc.Ulloa
D
125

I've been using:

await page.waitForTimeout(3000);

Where 3000 is Milliseconds And that seems to be working for me.

Deni answered 25/2, 2019 at 16:33 Comment(2)
waitfor() has been depricated. use page.waitForTimeout(1000) insteadOrnithic
page.waitForTimeout() is now obsolete. Replace with new Promise(r => setTimeout(r, milliseconds));Barimah
E
63

You can use one of the following options to wait for one second:

await page.waitFor(1000);
await frame.waitFor(1000);
await new Promise(r => setTimeout(r, 1000));

Alternatively, there are many Puppeteer functions that include a built-in delay option, which may come in handy for waiting between certain events:

// Click Delay
// Time to wait between mousedown and mouseup in milliseconds. Defaults to 0.

await page.click('#example', {delay: 1000});
await frame.click('#example', {delay: 1000});
await elementHandle.click({delay: 1000});
await page.mouse.click(0, 0, {delay: 1000});

// Type Delay
// Time to wait between key presses in milliseconds. Defaults to 0.

await page.type('#example', 'Hello, world!', {delay: 1000});
await frame.type('#example', 'Hello, world!', {delay: 1000});
await elementHandle.type('Hello, world!', {delay: 1000});
await page.keyboard.type('Hello, world!', {delay: 1000});

// Press Delay
// Time to wait between keydown and keyup in milliseconds. Defaults to 0.

await elementHandle.press('Backspace', {delay: 1000});
await page.keyboard.press('Backspace', {delay: 1000});
Eun answered 29/10, 2018 at 0:44 Comment(3)
waitFor is deprecated and will be removed. The new function is waitForTimeout github.com/puppeteer/puppeteer/issues/6214Dabble
waitForTimeout is also deprecatedThreecornered
Just addin to the discussion. If anyone hits problems of not getting elements, delay is one the best of options to keep the automation flow smooth and avoid errors (besides try and catch and else, of course)Pusillanimous
D
27

page.waitFor has now been deprecated.

page.waitForTimeout is now advised to pause script execution for the given number of milliseconds before continuing:

await page.waitForTimeout(1000)
Dasha answered 30/9, 2020 at 20:39 Comment(1)
update docs link pleaseReno
U
9

Other answers have shown how to sleep, but now that page.waitForTimeout is finally deprecated in 16.1.1 and was removed in 22.0.0, I figure I'd add the answer I've wanted to add for awhile:

Don't sleep! It causes a race condition that disrupts the event-driven nature of Puppeteer, introducing unnecessary brittleness. There's almost always a better predicate to wait on, either explicitly or using the Locator API:

  • Are you waiting for a CSS selector, aria label, text or XPath to appear? Try waitForSelector (optionally with the appropriate built-in selector).
  • Are you waiting for a navigation? Try waitForNavigation or adjust the waitUntil option on goto.
  • Are you waiting for a network event or state? Try waitForRequest, waitForResponse or waitForNetworkIdle.
  • Are you waiting for a popup? Try promisifying page.on("dialog", ....
  • Are you waiting for some arbitrary predicate, like a minimum number of child elements to appear? Try waitForFunction.
  • Something else? Run an evaluate block and add your own code to wait for a DOM mutation or poll with setInterval or requestAnimationFrame and effectively reimplement waitForFunction as fits your needs.

waitForFunction in particular is underused but it adds a huge amount of reliability and precision that waitForTimeout doesn't.

If all else fails and you have to block the script, you can delay, but I've written hundreds of Puppeteer scripts and have never had to use any sleep variant, so I'm pretty convinced it's basically unnecessary.

See my blog post on Puppeteer Antipatterns for more analysis of why you should avoid sleeping in any form except as an absolute last resort.

See also the Playwright docs for waitForTimeout, which is essentially the same as the Puppeteer method:

Discouraged

Never wait for timeout in production. Tests that wait for time are inherently flaky. Use Locator actions and web assertions that wait automatically.

One caveat to the above: sleeping can be useful for temporary debugging while developing a script.

Ulloa answered 11/9, 2022 at 3:15 Comment(1)
100% agree with this line "waitForFunction in particular is underused but it adds a huge amount of reliability and precision that waitForTimeout doesn't."Colucci
C
4

Try this function.

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

to use it

  async function demo() {
    console.log('Waiting...');
    await sleep(3000);
    console.log('ok');
  }

  demo();
Corycorybant answered 25/2, 2019 at 13:39 Comment(0)
S
-1
await new Promise(_func=> setTimeout(_func, 5000));
Salted answered 24/2, 2019 at 5:9 Comment(1)
Many other answers already offer this with a clear explanation. Renaming resolve to _func is odd. Not only that, we really shouldn't be using this in Puppeteer anyway if we can possibly help it.Ulloa

© 2022 - 2024 — McMap. All rights reserved.