Why is await not waiting for a promise to finish?
In my LWC, I am trying to call an Apex method and wait for it to finish. This is what it comes down to:
import apexMethodA from '@salesforce/apex/SomeControllerClass.apexMethodA'; export default class TradeWindow extends NavigationMixin(LightningElement) { initialJSfunction() { console.log('about to call waitForApexMethodA'); this.waitForApexMethodA(); console.log('finished calling waitForApexMethodA'); // More processing depending on the output of apexMethodA. } async waitForApexMethodA() { console.log('about to call apexMethodA'); try { await apexMethodA(); } catch(error) { console.log(error); } console.log('finished calling apexMethodA'); // Some more processing. } }
To my surprise/horror, this is what the console log shows:
about to call waitForApexMethodA about to call apexMethodA finished calling waitForApexMethodA finished calling apexMethodA
This is not what I expected and definitely not what I want. I have read lots of documentation about this and I had hoped that await would have the code wait until the Apex method returns with an answer, but apparently that is not how it works.
When I read Mozilla's documentation on this, it seems that await does not wait at all:
An await splits execution flow, allowing the caller of the async function to resume execution.
But in many other places, I read that await and async are the way to go.
My code is too complicated to solve this with a chain of .then's, I would like to solve it using await. How can I do that?
I tried to wrap the call to waitForApexMethodA in a Promise and await that, but of course, that doesn't work: as soon as await is encountered in waitForApexMethodA, control is returned to the caller. That is not what I want, initialJSfunction should only get control after all of waitForApexMethodA has completely finished.
You can mark the initialJSfunction as async and the method call inside it with await if await is not waiting. This would make the JS code wait until apex method execution is completed. So, your code snippet would be as shown below:
async initialJSfunction() { console.log('about to call waitForApexMethodA'); await this.waitForApexMethodA(); console.log('finished calling waitForApexMethodA'); // More processing depending on the output of apexMethodA. }
Note that marking a JS method as async doesn't really make it asynchronous, unless there are statements within the method marked with await. So, if you have any synchronous code execution in the initialJSfunction to be executed before apex method call, you would need to have it before the statement marked with await. Also, as mentioned here, too much usage of async-await could lead to performance issues, so use it with some due-diligence.
You could also do a mix of async-await & .then construct as shown in the snippet below:initialJSfunction() { console.log('about to call waitForApexMethodA'); this.waitForApexMethodA().then((data) => { console.log('finished calling waitForApexMethodA'); // More processing depending on the output of apexMethodA. }); // Some synchronous code here if you want some processing before the apex method execution completes }