3 min readRishi

Canvas Apps: Concurrent() Is How OnStart Stops Feeling Stuck

Canvas Apps: Concurrent() Is How OnStart Stops Feeling Stuck

OnStart that calls four data sources one after another makes the user stare at a spinner for the sum of four round trips. Those calls usually do not depend on each other. The account list does not need the choice column metadata. The current user's bookings do not need the product catalog. Concurrent() runs them together and finishes when the slowest one finishes, not when all of them have taken turns.

Concurrent(
    ClearCollect(colAccounts, Accounts),
    ClearCollect(colProducts, Products),
    Set(varMe, User())
);
Set(varReady, true);

varReady is the flag the first screen checks. Until it is true, show a skeleton, not a gallery bound to a collection that is still empty. An empty gallery that fills in later looks like "no rows," and people tap New.

What is safe to put in one Concurrent

A call is safe to run beside another when it does not read a variable or collection that the other call writes.

Safe togetherNot safe together
Two ClearCollects of different tablesA collect, then a Filter of that same collection
User() and a Dataverse listLookUp of a row whose id comes from the first LookUp
Several Set() of unrelated variablesPatch that must see the collection you are still loading

If you need the user's email before you can filter a list, that filter stays after the Concurrent, or it becomes its own second Concurrent once varMe exists. Nesting dependent work inside one Concurrent does not make it parallel. It makes the order undefined.

Delegation still applies

Concurrent does not raise the delegation limit. A Filter that cannot be delegated still returns a partial set, just sooner. If the gallery was wrong before, it is wrong faster now. Fix the filter — or move the query to a view — before you celebrate the spinner.

The same is true of ForAll inside OnStart. Parallelism does not forgive a loop that Patches a hundred rows on every launch. Load the rows. Patch when the user acts.

Where else it earns its place

OnVisible on a screen that opens a form is the second site. Load the record, the related contacts, and the choice labels together. The form's Item can bind immediately if you already have the record. The related gallery waits on its own collection. Users forgive a related list that fills in. They do not forgive a form that takes three seconds to show the name.

Do not wrap Navigate in Concurrent. Navigation is not a data call, and firing it beside a collect races the screen against the data. Set the collections, then navigate.

Time OnStart before and after on a device, not only in the studio. Studio monitor shows duration per formula. The number that matters is the gap between launch and varReady on a phone on the company network. If one call dominates, Concurrent will not hide it. That call is the one to cache, to narrow with a view, or to stop loading until the screen that needs it.

Keep reading

Newsletter

New posts, straight to your inbox

One email per post. No spam, no tracking pixels, unsubscribe anytime.

Comments

  • No comments yet. Be the first.