3

I want to delay making a call to another function in my forEach loop if a certain condition is met, but am not understanding setTimeout in this scenario.

function checkName(person) {
    console.log('checking name of ' + person.name)
    if (person.name === 'Julie') return true 
}

function checkPersons() {
    var persons = [
        {name: 'Bob', age: 21},
        {name: 'Frank', age: 15},
        {name: 'Julie', age: 12}
    ]

    var results = []

    persons.forEach(function(person) {
        if (person.age >= 18) {
            console.log('do not need to check name of ' + person.name)
            results.push(person)
        } else {
            setTimeout(function() {
                if (checkName(person)) {
                    console.log('Julie is ' + person.name)
                    results.push(person)
                }
            }, 5000)
        }        
    }) 
}

checkPersons()

https://jsfiddle.net/nicholasduffy/sy7qpqu1/1/

I get

do not need to check name of Bob
// 5 second delay here
checking name of Frank
checking name of Julie
Julie is Julie

I would like a 5 second delay each time I need to call checkName

do not need to check name of Bob
// 5 second delay here
checking name of Frank
// 5 second delay here
checking name of Julie
Julie is Julie
3
  • JS fires the timeout function async, which means the loop finishes, and the callback for setTimeout is called 5 secs later. The loop itself doesn't wait for the callback to be called. So the two callbacks fire nearly the same time. @juvian s comment is a workaround, to get the desired behaviour Commented Dec 16, 2015 at 16:04
  • the issue is that both your timeout's get created at the same time. setTimeout releases the main thread to continue, so the two calls happen (almost) instantaneously. If you do what @juvian says the time out's will be index times longer. Commented Dec 16, 2015 at 16:05
  • Got it, thanks. That quick fix has this working now. @juvian if you want to make an answer, I'll accept. Commented Dec 16, 2015 at 16:10

2 Answers 2

7

As others have mentioned, setTimeout is async, so js fires on the forEach all timeouts funcions, with a wait time of 5 seconds. So after 5 seconds, all run at the "same" time.

To avoid this, you could either do a queue and run just one timeout and when you finish call the next one, or in this case a simpler solution would be to just adjust the wait time according to the index of the person you are iterating:

persons.forEach(function(person, index) { // we add index param here, starts with 0
    //your code
    else{
        setTimeout(function() {
            if (checkName(person)) {
                console.log('Julie is ' + person.name)
                results.push(person)
            }
        }, 5000*(index+1)) // or just index, depends on your needs
    }        
}) 

This way, first one will run after 5 seconds, second one after 10, third one 15 and so on

Sign up to request clarification or add additional context in comments.

Comments

0
var index = 1;
persons.forEach(function(person) {
        if (person.age >= 18) {
            console.log('do not need to check name of ' + person.name)
            results.push(person)
        } else {
            setTimeout(function() {
                if (checkName(person)) {
                    console.log('Julie is ' + person.name)
                    results.push(person)
                }
            }, (index)*5000);
            index++;
        }        
    }) 

2 Comments

Please don't just dump code with no explanation - it's not even clear what you've changed without close inspection.
Good point @JamesThorpe for archival reference index was added to increment only when the setTimeout is initiated

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.