setTimeout Vs window.setTimeout

Hi folks,

Question about the code : Why is it that sometimes window.setTimeout is used instead of the global setTimeout ?

It is kind of an issue because I cannot use BabylonJs in a test environnement where window.setTimeout is not defined (not in the browser).

Yes, I can redefine window.setTimeout on my side but it might be better to always use the global setTimetout. Do that sound a good idea ? Can I make a PR for that ?

Thanks in advance for you anwser and Happy New Year to all of you :slight_smile:
Julien

you do realize the global object is the window object? Meaning writing “setTimeOut” is resolving to “window.setTimeOut”

Can you explain the context of where you are having issues and how it relates to Babylon?

My tests run in node with jest within a create-react-app, NOT in the browser.

If I don’t add some code like global.window.setTimeout = setTimeout I have this error when running the test :

    TypeError: window.setTimeout is not a function

      at Function.ThinEngine.QueueNewFrame (../lts/core/generated/Engines/thinEngine.ts:5896:27)
      at NullEngine.ThinEngine._queueNewFrame (../lts/core/generated/Engines/thinEngine.ts:1612:27)
      at NullEngine.runRenderLoop (../lts/core/generated/Engines/thinEngine.ts:1629:39)

Hello!

I’m sorry, but this is not true. For example NodeJS has it’s own setTimeout function and it returns a NodeJS.Timeout object:

however window.setTimeout returns a number:

So it is not the same.

1 Like

I am not very familiar with jest but I think it doesn’t have a DOM window object defined.
A simple google search may shed more light on the issue :slight_smile:

More info here:

I’m sorry but that is true, in the browser, calling window.setTimeout is equivalent to setTimeout. And that’s excactly what you mean when you say

that the global object is the window object

And in IMHO there is no point calling window.setTimeout, especially if both are used in the very same function :

    public static QueueNewFrame(func: () => void, requester?: any): number {
        if (!IsWindowObjectExist()) {
            if (typeof requestAnimationFrame !== "undefined") {
                return requestAnimationFrame(func);
            }

            return setTimeout(func, 16) as unknown as number;
        }

        if (!requester) {
            requester = window;
        }

        if (requester.requestPostAnimationFrame) {
            return requester.requestPostAnimationFrame(func);
        } else if (requester.requestAnimationFrame) {
            return requester.requestAnimationFrame(func);
        } else {
            return
                window.setTimeout(func, 16)
      }
    }

Whether setTimeout returns different type of value between in the Browser/NodeJs is another question, and actually the return type is not really problem as its only purpose is to identify the timer to be able to clear it with clearTimeout

Actually I just read more carefully the piece of I pasted above, the problem might come from that function. Testing if the window object is defined is not enough, we should also test if window.setTimeout exists

This absolutely depends on what environment is your app running in, but you can’t generalize this. Ofcourse if you open the console and try it there it’s true but you can’t rely on it in any other environment.

If this resolves to window.setTimeout

you wouldn’t need to cast to unknown because windows.setTimeout always returns a number so you are doing it to satisfy the TS compiler because it doesn’t know which version of setTimeout are you referring to.

Ok, you might have got me wrong, so I rephrase it:

in the browser, calling window.setTimeout is the very same thing as callling setTimeout, because window is the global object. So in this case, there is not difference. We could just call setTimeout.

If not in the browser, then window might not be the global object, that’s right, but also it might not has a setTimeout method. So we should make sure that window.setTimeout is defined before calling it and fallback to the global setTimeout if it is not defined.

1 Like

Buuut you can run a webpack/vite/parcel etc app in the browser where setTimeout could resolve not to the global window.setTineout function. :sunglasses: You know what I mean…

Sure. I’m not saying that window.setTimeout should not be called. I’m saying that we should make sure it exists before calling it.

By the way, having setTimeout and window.setTimeout to be different functions looks a bit dangerous to me, if not weird. And I’m not sure which one the user is expecting BabylonJs to call…

ok sorry , i didnt understand what was meant by “not in a browser” although I cant say im too happy to hear such things, fragmentation in how you have to write javascript now for different platforms or frameworks is not ideal.

1 Like

Bringing @RaananW on the loop

TypeScript helps as a lot when it comes to typing in different environments. If you use ReturnType<setTimeout> as the type of the object you get from a setTimeout call your framework (for example Babylon ;-)) can run in both node.js and the browser, even if they have a different return type for this specific function.

Having said that, I am officially criticizing Node.js for choosing to go this path, as it makes little sense to me to change a web standard just because you think you know better. I mean, they might know better, but that would only lead to problems in different environments. As we see here… But that’s a whole different story

2 Likes