Understanding asynchronous code in Babylon.js

Babylon.js
4 min readOct 30, 2020

--

One of my personal hills, that I’m ready to die for, is the opportunity to improve JavaScript by adding better threading support. So far the current state of that support is pretty limited to using WebWorkers which unfortunately cannot be as powerful as threads are in languages like C++ or C#.

I do not want to blame the browser vendors though, because this topic is quite complex and can come with a lot of pain.

That being said and with the current way of working in JavaScript, we can still feel a bit of what multithreading can be thanks to Promises (and asynchronous functions).

Aynchronous calls

Asynchronous calls are not really new to JavaScript. Every time we have a callback, we can consider that we are using some asynchronous code. Think for instance about any XMLHttpRequest calls. The call to the network resource will take time and thus a callback will be executed for when the data will be ready. This forces your code to not be written in a serial way anymore.

In Babylon.js, we encapsulated it into callbacks as well like, for instance, the Texture constructor which takes an onLoad and an onError callbacks.

Promises

Promises are (and by far) one of my favorite features that was recently added to JavaScript.

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

Going further

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
https://www.twitter.com/deltakosh

--

--

Babylon.js
Babylon.js

Written by Babylon.js

Babylon.js: Powerful, Beautiful, Simple, Open — Web-Based 3D At Its Best. https://www.babylonjs.com/

No responses yet