I do not want to blame the browser vendors though, because this topic is quite complex and can come with a lot of pain.
In Babylon.js, we encapsulated it into callbacks as well like, for instance, the Texture constructor which takes an onLoad and an onError callbacks.
It defines an object that will be used as a placeholder for the eventual result (or error) of piece of asynchronous code.
Since it was shipped to the major browsers (see support chart below) we added a lot of promises in Babylon.js like in the SceneLoader class.
As you can see, only Internet Explorer does not support promises but we’ve got you covered and Babylon.js will automatically load a promise polyfill if it is running on IE so you can confidently use promises all the time.
So this code will be able to run everywhere:
Or even better, you can now take advantage of the async/await pattern (but is won’t work on IE anymore):
Isn’t it lovely?
“Promisifying” your code
If you are like me and you love using promises (As they make the code cleaner) you will find places in the engine where you could use some async but there is no direct function to do it.
Not a problem! You can create your own promises and join the fantastic world of asynchronous programming.
To illustrate that, let’s take an example where you want to load 2 textures and when they are loaded (see? as soon as you use that construct “when something”, you know that this is a good candidate for a promise) we would like to use them with a material.
So we want to create a function that will return a promise and that promise will resolve when both textures are loaded. Something like that:
We are creating and returning a promise but we are not resolving the promise (by calling resolve()). So ultimately the question here is: how can I use the callbacks from the textures to ensure that both textures are ready?
First option will be to use the texture onLoad callbacks but I would like to go with a more generic approach (one that will work for textures or anything based on Observables which is a concept heavily used in Babylon.js).
The basic idea is to rely on the texture.onLoadObservable to decrement a counter. When that counter will be zero, we can resolve the promise:
So with this function in mind, here is our final code:
And now that we have that function, making sure that our two textures are loaded is quite easy and elegant:
By default, Babylon.js is actually providing that WhenAllReady function but through a callback so here is a playground where I’m transforming it into a promise: https://www.babylonjs-playground.com/#XKSKJN
Now that you know how to create promises, you can create cleaner code (less spaghetti code for sure!).
Feel free to come share what you did on our forum!
David ‘Deltakosh’ Catuhe