My actual use case is batching a bunch of network calls (input: an array of args objects), and packaging the results (output: a corresponding array of specific success/failure replies for each request). My goal is to not have to pollute the rest of my code with async/await when calling this batching function. I want the batching call (here, represented by MySyncFunction
) to be called synchronously (as it is in TestCaller
), even though internally it uses asynchrony to offload IO costs. In a nutshell, I just want MySyncFunction
to resolve all promises before returning, and not continue in its parent.
What I provide below is a minimally reproducible example of the logic of my problem.
function sleep(ms : number): void
{
return new Promise(resolve => setTimeout(resolve, ms));
}
//notice: no async here
function MySyncFunction(): string[]
{
const result : string[] = [];
async function MyAsync_BeginEnd(): Promise<void>
{
console.log("MyAsync_Begin");
result.push("Alice");
await sleep(1000);
console.log("MyAsync_End");
result.push("Charlie");
}
async function MyAsync_Middle(): Promise<void>
{
await sleep(100);
console.log("MyAsync_Middle");
result.push("Bob");
}
async function MyAsyncFunction(): Promise<void>
{
const promise1 = MyAsync_BeginEnd();
const promise2 = MyAsync_Middle();
await promise1;
await promise2;
}
// supposed to resolve everything before moving on
(async () => await MyAsyncFunction())();
return result;
}
function TestCaller():void
{
console.log("Before MySyncFunction");
const strarr: string[] = MySyncFunction();
console.log("After MySyncFunction; ", strarr);
}
TestCaller()
You can run it (once saved in a file called test_async_await.ts
) with tsc --target es6 --lib es2015,dom test_async_await.ts && node test_async_await.js
With the preceding code, which does compile and run, I am expecting the logs to read:
Before MySyncFunction
MyAsync_Begin
MyAsync_Middle
MyAsync_End
After MySyncFunction; [ 'Alice', 'Bob', 'Charlie' ]
since MySyncFunction
is synchronous.
However, they instead read:
Before MySyncFunction
MyAsync_Begin
After MySyncFunction; [ 'Alice' ]
MyAsync_Middle
MyAsync_End
as if MySyncFunction
was declared to be asynchronous !
Questions:
is this behavior intentional ? If so, why ? Is it maybe a bug to report ? I'm told asynchrony in Rust (for example) isn't like that, and works as I'd expect.
how do I effectively resolve the promises internally so that
MySyncFunction
can be called synchronously, without needingawait
orthen
?
I have looked at the following:
asynchronous function within synchronous function in Javascript
How to return the response from an asynchronous call
Using "await" inside non-async function
But they do not solve my problem.
EDIT:
FYI, the following does not work either.
async function MyAsyncFunction(): Promise<void>
{
const promise1 = MyAsync_BeginEnd();
const promise2 = MyAsync_Middle();
// await promise1;
// await promise2;
Promise.all([promise1, promise2]);
}