Loading states for JavaScript actions are weird

So I’ve noticed that when using actions with only JavaScript steps in the “Show Loading” setting of components, and the code is all synchronous, the loading never actually shows/updates properly.

For example, here is an action that calculates the factorial of the numbers 0 to 9999:

var f = [];
function factorial (n) {
  if (n == 0 || n == 1)
    return 1;
  if (f[n] > 0)
    return f[n];
  return f[n] = factorial(n-1) * n;
}

const ret = Array(10000).fill(null).map((_,i) => factorial(i));
return ret;

On average, it takes around 0.5 ms, which is not a lot, but it should still show the loading on the component for a very brief moment, but it doesn’t:

Loading state not showing

But if we add something asynchronous to the action, it does show. For example, I’ll add await new Promise(r => setTimeout(r,0)); at the very beginning. Now the loading state is visible:

loading

I have other examples, but I think my issue is clear. This makes it quite bothersome to work with loading states, since it requires you to have at least one asynchronous operations in actions you’ll use for the Show Loading setting.

Maybe I’m also doing something wrong?

Hi @Max

I’ll consult with the dev team about it.

1 Like

Hi @Max

You’re not doing anything wrong here.

This happens because fully synchronous JavaScript actions can start and finish within the same browser render cycle. UI Bakery does set the action loading state, but if the action completes immediately, the browser may only render the final state, where loading is already false.

As a workaround, add a tiny async boundary at the beginning of JS-only actions that you want to use with Show Loading:

await new Promise(resolve => setTimeout(resolve, 0));

So your action would start like this:

await new Promise(resolve => setTimeout(resolve, 0));

var f = [];
function factorial(n) {
  if (n == 0 || n == 1) return 1;
  if (f[n] > 0) return f[n];
  return f[n] = factorial(n - 1) * n;
}

const ret = Array(10000).fill(null).map((_, i) => factorial(i));
return ret;

This gives the browser a chance to render the loading state before the synchronous calculation continues. We’ll treat this as a product/runtime issue on our side, because Show Loading should behave consistently for JS-only actions too.

1 Like

Hi @Kate, thanks for reporting back!

I was already thinking that it would be something like that, good to know for sure though!

If I remember correctly, there were already discussions here in the community about generally improving the JavaScript action step in terms of usability, engine, etc. so this could also be worked on at that time.

1 Like