copyflake
copyflake

Reputation: 7127

Wait 5 seconds before executing next line

This function below doesn’t work like I want it to; being a JS novice I can’t figure out why.

I need it to wait 5 seconds before checking whether the newState is -1.

Currently, it doesn’t wait, it just checks straight away.

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}

Upvotes: 664

Views: 2090982

Answers (15)

Leandro Carvalho
Leandro Carvalho

Reputation: 350

Works like a charm on 2024-02:

It needs to go easy and simulate the user's interaction:

setInterval(() => {
    // if page is empty, then click on reload
    if (document.getElementsByClassName("no-user-text ng-star-inserted").length === 1) {
        reloadUsers();
    }
    else {
        deleteUserAccount();
    }
}, 2000);

const delay = ms => new Promise(res => setTimeout(res, ms));

const reloadUsers = async () => {
    document.querySelectorAll("[data-test-id='reload-user-button']")[0].click();

    await delay(3000);
}

const deleteUserAccount = async () => {
    let confirmationDialogIsClosed = document.getElementsByClassName('confirm-button mdc-button mdc-button--raised mat-mdc-raised-button mat-warn mat-mdc-button-base').length === 0;
    if (confirmationDialogIsClosed) {
        // click on 3 dots next to user
        document.getElementsByClassName('mat-mdc-menu-trigger mat-mdc-tooltip-trigger edit-account-button mdc-icon-button mat-mdc-icon-button mat-unthemed mat-mdc-button-base')[0].click();

        await delay(200);

        // click on delete account
        let contextMenuWithOptions = document.getElementsByClassName('mat-mdc-menu-item mat-mdc-focus-indicator ng-star-inserted');
        contextMenuWithOptions[contextMenuWithOptions.length - 1].click();       
    }

    await delay(1000);
    // click on delete in confirmation dialog
    document.getElementsByClassName('confirm-button mdc-button mdc-button--raised mat-mdc-raised-button mat-warn mat-mdc-button-base')[0].click();
}

Upvotes: 5

Mic
Mic

Reputation: 4004

You really shouldn't be doing this, the correct use of timeout is the right tool for the OP's problem and any other occasion where you just want to run something after a period of time. Joseph Silber has demonstrated that well in his answer. However, if in some non-production case you really want to hang the main thread for a period of time, this will do it.

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

With execution in the form:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

I've arrived here because I was building a simple test case for sequencing a mix of asynchronous operations around long-running blocking operations (i.e. expensive DOM manipulation) and this is my simulated blocking operation. It suits that job fine, so I thought I post it for anyone else who arrives here with a similar use case. Even so, it's creating a Date() object in a while loop, which might very overwhelm the GC if it runs long enough.
But I can't emphasize enough, this is only suitable for testing, for building any actual functionality you should refer to Joseph Silber's answer.

Upvotes: 277

Sanjeet kumar
Sanjeet kumar

Reputation: 3441

If you want to wait twice in React.

function WaitComponent() {
  const [isWaitTimeOver, setWaitTimeOver] = useState(false);
  const timerIdRef = useRef <number | null> (null);

  useEffect(() => {
    const wait = (time: number, count: number) => {
      timerIdRef.current = window.setTimeout(function () {
        if (count < 1) {
          setWaitTimeOver(true); // this will rerender the useEffect
        } else {
          clickHandler();
        }
      }, time);
    }

    wait(5000, isWaitTimeOver ? 1 : 0);


    return () => {
      if (timerIdRef.current) {
        clearTimeout(timerIdRef.current);
      }
    }
  }, [isWaitTimeOver])
}

Upvotes: 0

Shl
Shl

Reputation: 3688

If you're in an async function you can simply do it in one line:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

FYI, if target is NodeJS you can use this built-in function if you want (it's a predefined promisified setTimeout function):

import { setTimeout } from 'timers/promises';

await setTimeout(3000); // 3 sec

Upvotes: 206

sumsumcity
sumsumcity

Reputation: 487

If you have an asyn function you can do:

await new Promise(resolve => setTimeout(resolve, 5000));

Upvotes: 12

Etienne Martin
Etienne Martin

Reputation: 11569

Browser

Here's a solution using the new async/await syntax.

Be sure to check browser support as this is a language feature introduced with ECMAScript 6.

Utility function:

const delay = ms => new Promise(res => setTimeout(res, ms));

Usage:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

The advantage of this approach is that it makes your code look and behave like synchronous code.

Node.js

Node.js 16 provides a built-in version of setTimeout that is promise-based so we don't have to create our own utility function:

import { setTimeout } from "timers/promises";

const yourFunction = async () => {
  await setTimeout(5000);
  console.log("Waited 5s");

  await setTimeout(5000);
  console.log("Waited an additional 5s");
};

⚠️ Just for the record, you might be tempted to use a wait function to circumvent race conditions (when testing asynchronous code for example). This is rarely a good idea.

Upvotes: 659

hackernewbie
hackernewbie

Reputation: 1712

setTimeout(function() {
     $('.message').hide();
}, 5000);

This will hide the '.message' div after 5 seconds.

Upvotes: 18

p.durga shankar
p.durga shankar

Reputation: 1217

You can add delay by making small changes to your function ( async and await ).

const addNSecondsDelay = (n) => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, n * 1000);
  });
}

const asyncFunctionCall = async () {

  console.log("stpe-1"); 
  await addNSecondsDelay(5);
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();

Upvotes: 6

Avatar
Avatar

Reputation: 15156

Use a delay function like this:

var delay = ( function() {
    var timer = 0;
    return function(callback, ms) {
        clearTimeout (timer);
        timer = setTimeout(callback, ms);
    };
})();

Usage:

delay(function(){
    // do stuff
}, 5000 ); // end delay

Credits: How to delay the .keyup() handler until the user stops typing?

Upvotes: 54

bearacuda13
bearacuda13

Reputation: 1854

This solution comes from React Native's documentation for a refresh control:

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

To apply this to the OP's question, you could use this function in coordination with await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}

Upvotes: 13

jfriend00
jfriend00

Reputation: 707158

You should not just try to pause 5 seconds in javascript. It doesn't work that way. You can schedule a function of code to run 5 seconds from now, but you have to put the code that you want to run later into a function and the rest of your code after that function will continue to run immediately.

For example:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

But, if you have code like this:

stateChange(-1);
console.log("Hello");

The console.log() statement will run immediately. It will not wait until after the timeout fires in the stateChange() function. You cannot just pause javascript execution for a predetermined amount of time.

Instead, any code that you want to run delays must be inside the setTimeout() callback function (or called from that function).

If you did try to "pause" by looping, then you'd essentially "hang" the Javascript interpreter for a period of time. Because Javascript runs your code in only a single thread, when you're looping nothing else can run (no other event handlers can get called). So, looping waiting for some variable to change will never work because no other code can run to change that variable.

Upvotes: 49

Sylhare
Sylhare

Reputation: 7059

Based on Joseph Silber's answer, I would do it like that, a bit more generic.

You would have your function (let's create one based on the question):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

And you could have a wait function:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

At the end you would have:

wait(5000, videoStopped, newState);

That's a solution, I would rather not use arguments in the wait function (to have only foo(); instead of foo(arg);) but that's for the example.

Upvotes: 6

Steve Jiang
Steve Jiang

Reputation: 743

Try this:

//the code will execute in 1 3 5 7 9 seconds later
function exec() {
    for(var i=0;i<5;i++) {
        setTimeout(function() {
            console.log(new Date());   //It's you code
        },(i+i+1)*1000);
    }
}

Upvotes: 10

Jitendra Pal - JP
Jitendra Pal - JP

Reputation: 242

Best way to create a function like this for wait in milli seconds, this function will wait for milliseconds provided in the argument:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}

Upvotes: 5

Joseph Silber
Joseph Silber

Reputation: 219920

You have to put your code in the callback function you supply to setTimeout:

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

Any other code will execute immediately.

Upvotes: 499

Related Questions