Wrapping Asynchronous (then do) blocks into a Synchronous Function resolves unpredictable results

Thunkable provides an extensive library of calls to external services including Google Docs and Web APIs. These external calls are, by necessity, asynchronous calls. That is, the request is sent to the external serivce, Thunkable block execution continues on it’s merry way, then the external service sends a reply. Thunkable wraps the external calls in in blocks with “Then Do” sections. This is a massive improvement over separate call and response block (MIT App Inventor), but it is not without challenges.

These asynchronous calls are particularly problematic when trying to loop through a list and make an external service call (e.g. Add to Data Source, make a Web API call).

Loops like this result in either Thunkable crashing or erratic results. Wait blocks can help, but the still produce unreliable results.

The blocks below illustrate how you can convert an asynchronous external call into a synchronous function, eliminating the irregularities associated with external calls within loops.

Let’s break it down.

#1 Looping through a collection. This could be any loop, either a collect or a for x to y. Because the example asynchronous call is for a mapping API, it is a list of coordinates.

#2 Wrap the Web API call in a function. To keep the loop working correclty, the web_API call ( asychronous process) is wrapped in a function (aka a facade). By using a function wrapper, it forces the web API call to act like any other synchronized Thunkable block (e.g. Set Value to …).

#3 Call…Waiting. First, and most importantly, the result variable is set to an empty value as the first step in the function. If you don’t do this, nothing will work.


The external call’s results are placed in a Thunkable variable. This acts as a trigger for the next step, the waiting. The Repeat Until loop continues until the Result value is not blank. That keeps Thunkable waiting until the Web_API call finishes, no matter how long that make take. Also notice that regardless of success or error, a Result value is set.

The wait block and label updates are not essential, but help make progress easier to evaluate.

Although this example use the Web API, Data Source call can (should) also be wrapped in this way when looping is required.

As a note to Thunkable Staff ( Steven, domhnallohanlon, Jane, Thunkable Staff) might want to consider a similar built-in strategy. Asynchronous processes is a pretty advanced concept for a tool designed for new programmers. I L-O-V-E that Thunkable came up with a strategy to combine submit and response blocks (a la MIT App Inventor) into a single block. The next logical step is to build the wait into the block so novices can treat Web_API calls like Set Label blocks.

Here’s a remixable link
https://x.thunkable.com/copy/76f2b56e480eefb0320e027b3b845d76

P.S. I found that occasionally the Web API service (or other asynchronous process) will not respond. The above example will loop indefinitely in that case. To prevent an infinite loop, I added a WaitCounter variable which will trigger a break out of the REPEAT UNTIL frame after a set number of loops. In my case I wait for 10 second (20 loops with a 0.5 second wait).

6 Likes

Nice work! You made a nice logic gate there!

2 Likes

Can’t wait to try this out! But 1/2 a second (Wait 0.5 seconds) seems like a long delay. Did you have any luck with shorter delays?

1 Like

Depends on the call. As you can see from the screen shot, for this web_api, is was about a second to get a response. You can go with any length (1, 0.1, 0.000000001, etc). You could also include no wait at all. I just added the wait to reduce the number of “waiting…” entries in the label.

1 Like

Yeah, I might try it with no wait or a short delay such as 0.03 seconds. In my case, I don’t need to alert the user so it’s just going to be a background task to make sure the API call or Create Row block completes.

2 Likes

I have been pulling my hair out over this!! I made a call and even though I could see that the result was there the actions following were not picking it up.

I have made a change. It is basically your solution but I have externalised the loop controller so it is separate from the call data.

1 Define a new variable called syncAPI
2 Set to “true” just before the call
3 Set to “false” as the last step of the do block.
4 Add a repeat until loop after the call with a 0.1 second delay. I tried no delay but it didn’t re-test the syncApi variable and just looped indefinitely

For people who need a faster break-out maybe just increment a counter or just include an if statement with a break on true condition.

2 Likes