在函数启动时,我必须做一些异步工作,例如从Google secrets Manager中获取机密,并根据这些机密初始化客户端对象。我应该如何构建我的代码,使我的函数异步初始化,并且可以访问初始化的对象而不等待它们?
如果不遇到竞争条件,就无法确保在触发函数之前完成初始化。await
相当于somePromise.then(() => /* next bit of code */)
的语法糖,并且是非阻塞(如果您await
有什么东西,其他代码仍然可以执行,只有当前函数会暂停(。
虽然您可以在其他语言中使用while
循环来等待某个任务在另一个线程上完成,但JavaScript是单线程的,这样的while
循环会阻止初始化代码的运行。您需要使用回调或Promise
才能正确执行此操作。在这两个选项中,我会选择Promise
方法。这将允许您调用await init()
,如果您将promise缓存在init()
中,那么在您需要使用该函数时,它可能已经完成,并且它将立即返回结果。这为您省去了处理包含所需数据的对象的生命周期管理、编写代码以检查是否完成、处理初始化过程中的任何错误以及将来的麻烦。
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;
}