Hi @mishav, Hey, I found a very âBubblyâ way â and âToolboxyâ way â to ensure that long-loading scripts (such as moment / moment-timezone) are loaded before firing off an Expression.
(As a quick recap: My use case has been that Iâve modified the âcustom calendarâ technique originally offered by @codurly to work in a more âtimezone-awareâ way. The new Expression code that generates the calendar dates does so using moment/moment-timezone. The issue of late has been that â unless the scripts for those are put into the HTML header of the page, the Expression will try to fire BEFORE those libraries are fully loaded.
And as you and I recently discovered, making the Expression code only load on âPage is loaded (entire)â is not 100% bulletproof. In fact, that event can happen substantially before moment/moment-timezone is ready.
I recently took the Calendar widget Iâd built and turned it into a Reusable Element, further complicating the script loading issue. I didnât want to have to move the scripts that the RE relies on into the parent page itself⌠And I also didnât want to waste time loading those scripts twice [even though thatâs not really an issue with moment, but of course it could be with some other types of scripts].)
So hereâs what Iâve done:
In my case, there are in fact 2 things to wait for. First, moment
will become ready and afterward the moment-timezone
functions (moment.tz) will become ready. Hereâs how I check for those and how Iâve configured the Expression element:
1. Rather than executing the Expression code on âpage is loaded (entire)â, Iâve set it to wait until the value of a JS to Bubble element reaches a certain status value. Like this:
2. In my REâs equivalent of âwhen page is loadedâ workflow, I have a Run Javascript step. What this JavaScript does is evaluates the âtypeofâ of moment. This seems to be the most correct JavaScript way of evaluating whether or not a function is ready to go. If moment() is not yet callable, evaluating typeof(moment) will return âundefinedâ. If it ready, typeof(moment) will return âfunctionâ. Note that evaluating typeof does not actually call or attempt to trigger the function, so errors are avoided.
If moment is not yet ready, the script executes setTimeouts iteratively until it is. (This of course doesnât block execution of anything as itâs all asynchronous JavaScript.) That looks like this:
Youâll see that on success, we fire bubble_fn_moment(1). That JS to Bubble element is set to trigger and, on reaching this state, executes the next step of our wait, which is just like the first stepâŚ
3. But now we are waiting for moment.tz
to be callable. Like this:
On success, this Run JavaScript fires bubble_fn_moment(2), indicating that we are done waiting.
Upon reaching the value of 2, the Expression element becomes active as configured in Step 1, above.
This technique seems to be both quite performant and very reliable.
Testing with CPU throttling, slowed network, and cache disabled in Chrome Dev Tools yields console logs that look like this:
Youâll note that we waited for about 800 ms for moment to load beyond when Bubble tells us âpage is loadedâ, and an additional 100-200 ms for moment.tz to become fully ready.
Without throttling, we of course wait much less. Hereâs what that looks like on my machine with net and cpu unthrottled (but still disabling cache to ensure we are not fetching these things from local storage):
Seems to work just fine, so thought Iâd share this idea with you.