279
Views
2
Comments
Solved
Handling asynchronous JavaScript in Client Actions
Application Type
Mobile, Reactive

Hi!

I am creating a reusable component that wraps STRICH, a popular JavaScript barcode scanning library (I am the author of STRICH).

What I've achieved so far in my personal environment:

  • Created a demo app that scans barcodes using STRICH
  • The component and all STRICH-specific code is in a library module, which is a dependency of the demo app.
  • The main export of the library is a Block defining where to put the BarcodeReader and exposing some configuration options as input parameters.
  • Scanned barcodes are emitted as events to consumers.

So far, so good... what I'm struggling with is asynchronous JavaScript (Promise/async/await) in Client Actions.

I am using the onReady Client Action to initialize the JS library, which involves license checking and camera aquisition which is asynchronous. Ideally I'd like onReady to only complete when a certain Promise resolves. The result of onReady() is stored in a local variable (in this case, a Promise). In the onDestroy Client Action, I am tearing down the previously initialized infrastructure, which is again asynchronous, but much faster than the onReady code, as it does not require a network request.

What I'm wondering is:

1) Is there support for asynchronous JS in lifecycle callbacks (onReady/onDestroy), e.g. waiting until the Promise resolves/rejects in the lifecycle callbacks? If not, what would be a good way of working around the limitation – maybe a custom 'onBarcodeReaderReady()' that is emitted when everything is initialized?

2) If screen A navigates to screen B, screen A's onDestroy will be called *after* screen B's onReady. This is a bit problematic for my library, as a barcode reader needs to be destroyed *before* instantiating another, because otherwise A is still accessing the camera. Are there ways to be notified when a destroy is "pending", like a "beforeDestroy" hook?

3) In the same vein, is it possible to block navigation while a Promise is still pending? It would be useful to await full destruction/releasing of camera before continuing to a next screen.

4) Unrelated: the Block should also expose methods (start, stop to resume/pause barcode detection). My initial thought was to add Client Actions to the block, but it seems those can't be called from "outside". Is there an established pattern to mutate state in a Block from its Consumers? Setting an 'enabled' property would work too, I just need to have a way of mapping it to a JavaScript invocation on the underlying managed object.

Kind Regards

UserImage.jpg
Fernando Costa
Solution

1) Regarding the asynchronous actions, you can find help here. You have $resolve() and $reject() actions to properly handle the promise.

2) & 3) The navigation part is tricky. My suggestion would be to have a screen action to to destroy and then navigate. If i'm not mistaken, the platform only moves to the next node once the promise is handled. An alternative would be to check if the library is already initialized, and handle from there.

4) You could either do it with input parameters or plain old javascript. A proper example can be found here. Just make sure to properly document the webblock description so that people know which methods are available.

Best regards,

2024-03-18 10-31-07
Alex Suzuki

Hi Fernando

Thank you for your response. I'm marking it as solved, but unfortunately it seems that the lifecycle events like onInitialize, onReady, onDestroy etc. do not support asynchronous execution. I stumbled upon a forum post where someone observed the same behavior, and also created a minimal block with an asynchronous onReady that initializes a local variable after 5 seconds and calls $resolve(), and an onDestroy that logs the variable. onReady() is not awaited... onDestroy is allowed to run before onReady resolves(). It seems like the framework simply doesn't await lifecycle callbacks.

Regarding 2 + 3) yes, those are the workarounds that I see too.

Regarding 4) the input parameter/onParametersChanged worked well for me, but it's good to know that you can use JS to expose a block's Actions. Feels a bit hacky though.

Kind Regards

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.