Calling several futures in parallel (in Motoko)

In JavaScript there is Promise.all to wait at once for several futures. Is there (or can be implemented?) a similar thing in Motoko?

I want to wait for skExists from several CanDB canisters to securely check whether a key exists in the CanDB DB. Is it possible?

1 Like

There is no Promise.all in Motoko and it’s currently not possible to author a fully generic one.

However, you can do parallel waiting by issuing several sends and only awaiting the results later.

‘’’
let p1 = a1.send();
let p2 = a2.send();
let r1 = await p1;
let r2 = await p2;
‘’’

2 Likes

No, @claudio , your code first blocks on await p1 and only then moves to await p2.

Probably, this will work:

let p1 = a1.send();
let p2 = a2.send();
let r = [await p1, await p2];

But I am unsure even on the last code.

That is exactly how a Promise.all works.
You will only be waiting as long as the longest call.

Either p1 takes longer, than you do not need to wait on p2.
Or p1 finishes and you will also have to wait for p2.

There is no real difference between:

1 Like

@claudio You seem to think that

let r1 = await p1;
let r2 = await p2;

executes in parallel.

That’s not the case! await like any other language construct is executed sequentially.

await p1 blocks that is not allows to execute any more code in this thread of control until p1 finished. Only then await p2 is executed.

I will present another example to illustrate my point:

let r1 = await p1;
Debug.print("in the middle");
let r2 = await p2;

If await p2 executed in parallel with await p1, then in the middle would be printed after await p2, not before. That’s not the case.

@claudio Oh, I misunderstood you:

await p1;
await p2;

is really equivalent to Promise.all in JavaScript, because it finishes as soon as both p1 and p2 finish.

@claudio

However, no:

a1.send() does not start execution of an async function a1.send, it just returns a future (if Motoko works the same as most asynchronous languages).

So, in

let p1 = a1.send();
let p2 = a2.send();
let r1 = await p1;
let r2 = await p2;

execution of a2 starts only after execution of a1 finishes.

1 Like

Both messages are enqueued at send() and actually both sent at the first await. If destined at two different receivers, they can execute concurrently and, after the second await, will both have finished.

Motoko futures are eager, not lazy. Even if you don’t await a future, its effects still happen.