I have to do some asynchronous work at the startup of my function, for example grabbing secrets from Google Secrets Manager and initializing client objects based on those secrets. How should I structure my code so that my function is initialized asynchronously and can access initialized objects without awaiting them?
1 Answers
Without running into race conditions, there's no way to guarentee that your initialization has completed prior to your function being triggered. await
is pretty much syntax sugar for somePromise.then(() => /* next bit of code */)
and is non-blocking (if you await
something, other code can still execute, just the current function will pause).
While you could use a while
loop in other languages to wait for some task to complete on another thread, JavaScript is single-threaded and such a while
loop would stop your initialization code from ever running. You need to either make use of a callback or Promise
in order to do this properly. Of these two options, I would choose the Promise
method. This will allow you to call await init()
and if you cache the promise inside init()
it may be already completed by the time you need to use the function and it will immediately return the result. This saves you the hassle of having to deal with life-cycle management of an object that contains the data you need, writing the code to check if it's finished, handling any errors from initialization and the head scratching from future you.
async function _initDoTheWork() {
/*
* Take care of any async initialization here,
* and return any result as applicable
*/
const app = firebase.initializeApp();
return { app }; // just as an example
}
/**
* Starts the initialization function, but
* caches its promise to reuse in future calls
*/
function initDoTheWork() {
if (!initDoTheWork.promise) {
initDoTheWork.promise = _initDoTheWork();
}
return initDoTheWork.promise;
}
// trigger async work now
// ignore result, but trap errors so you don't get an Unhandled Rejection Exception
initDoTheWork()
.catch((err) => {
// you could do nothing here, but I'd log the error somewhere
console.error("Pre-initialization reported an error", error)
});
export async function doTheWork() { // the actual function to be exported
const { app } = await initDoTheWork();
const db = app.firestore();
// do stuff with app & db
}
/**
* Force reinitialization of doTheWork()
*
* Note: Errors must be handled by the caller.
*/
doTheWork.reinitialize = async function reinitialize() {
initDoTheWork.promise = _initDoTheWork();
return initDoTheWork.promise;
}

- 23,122
- 4
- 30
- 54
-
This [other answer](https://stackoverflow.com/a/66815121/3068190) may also be relevant. – samthecodingman May 12 '21 at 02:11