React: setTimeout not working on initial render

Created on 2 Jan 2018  路  6Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?
Bug, I think unless this behavior is intentional.

What is the current behavior?

You can see it here: https://jsfiddle.net/wunmrhcj/

Basically I am trying to batch a set of ajax calls by wrapping them in a promise that calls setTimeout. I've replaced actually ajax calls with calls to console.log() but the affect is the same. The first time the update function is called you can see the console log each statement within a single ms of each other statement. The next time the update function is called (12 seconds later) you can see that the console log statements are delayed as expected.

What is the expected behavior?

I expect the sleep function to work the first time it is called. As it stands now my UI is broken until the interval calls the update function again (which is 3 minutes in production).

I understand async stuff in React is a lil funky and I definitely don't know how React works under the hood so this could be intentional behavior somehow. If it is, why is it needed and is there any workaround so that I can get the behavior I need? Thanks guys and keep up the great work.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

React 15 but I believe this happens on React 16 as well. I'm on Firefox Developer Edition 57.0b7

Needs More Information

Most helpful comment

I think your mental model of how await works is slightly wrong. Try to mentally translate it into callbacks and you鈥檒l probably see the mistake.

If you make the outer function async and replace forEach with a regular for loop you鈥檒l get the desired behavior.

All 6 comments

Why do you think this is related to React? It doesn't override globals like setTimeout.

I don't understand from your description what the expected behavior is.

The first time the update function is called you can see the console log each statement within a single ms of each other statement. The next time the update function is called (12 seconds later) you can see that the console log statements are delayed as expected.

"Delayed" how? I see 10 calls within a few ms the first time, then another 10 calls within a few ms the second time, etc. Which is exactly what I'd expect from the code too. You don't explain what is unexpected about it. It's not obvious.

I expect the sleep function to work the first time it is called.

What does "work" mean? There's definitely a 1 second pause between update() itself and those console.log calls. (You can check by putting console.log in the update() itself.) Why do you say sleep() does not "work"?

As it stands now my UI is broken until the interval calls the update function again (which is 3 minutes in production).

This doesn't help either because you haven't stated what exactly you consider "broken".

@gaearon

I am just assuming it has something to do with React because I'm not sure what else would be causing this.

"Delayed" how?

In production what I expect to happen is essentially

arr.forEach(async item => {
  await sleep(1000)
  //make api call
})

so wait 1 second, then make an API call. When my component renders, this doesn't happen and I get rate limited. After 3 minutes this happens again and there is 1 call per second and I am not rate limited.

What does "work" mean? There's definitely a 1 second pause between update() itself and those console.log calls. (You can check by putting console.log in the update() itself.) Why do you say sleep() does not "work"?

To clarify, I'm not trying to delay the update method, I'm trying to delay the network calls that happen in the update method so that they happen approximately once a second. This doesn't happen on my initial render (i.e. it doesn't work because it is happening more than once per second) but the second time that method is called it does happen.

If you're confident this has absolutely nothing to do with React I trust your judgement and can look elsewhere for a solution.

I think your mental model of how await works is slightly wrong. Try to mentally translate it into callbacks and you鈥檒l probably see the mistake.

If you make the outer function async and replace forEach with a regular for loop you鈥檒l get the desired behavior.

Btw I would鈥檝e understood your original issue if you wrote you expect a one second interval between each of the items (rather than once before them all).

Was this page helpful?
0 / 5 - 0 ratings