我在Firebase中有一个云函数,在一系列promise调用中,它以对以下函数的调用结束:
function sendEmail() {
return new Promise((accept) => {
const Email = require('email-templates');
const email = new Email({...});
email.send({...}).then(() => {
console.log('Email sent');
}).catch((e) => {
console.error(e);
});
accept();
});
}
我很清楚email.send((返回一个promise然而,这种方法有一个问题,那就是,如果我要将函数更改为:
function sendEmail() {
const Email = require('email-templates');
const email = new Email({...});
return email.send({...});
}
它通常会导致UI挂起相当长的时间(10秒以上(,因为从承诺到解决所需的时间等于发送电子邮件所需的长度。
这就是为什么我认为第一种方法会更好。只需异步调用email.send((,它最终会发送电子邮件,并向客户端返回一个响应,无论电子邮件是否已经完成往返。
第一种方法是给我出问题。云功能必须更快地完成执行,从而为用户提供更好的体验,然而,电子邮件在15分钟以上的时间内不会发送。
我正在考虑另一种方法,我们有一个单独的云功能挂钩来处理电子邮件发送,但我想先问StackOverflow。
我认为这里混合了两个方面。
问题的一个方面涉及云功能背景下的承诺。在调用res.send()
之前,需要解决云函数中的承诺,因为在该调用之后,函数将立即关闭,并且不能保证未解决的承诺会在函数实例终止之前完成,请参阅此问题。您最好不要调用res.send()
,而是返回承诺的结果,如Firebase文档中所示,这里的关键是确保承诺得到正确解决,例如使用return myPromise().then(console.log);
这样的习惯用法来强制解决承诺。
另外,正如Bergi在评论中指出的那样,第一个片段使用了带有promise的反模式,第二个片段更加简洁明了。如果您在UI中遇到延迟,那么执行很可能在等待Function响应时被冻结,您可能会考虑在您的特定用例中是否可以避免这种情况。
话虽如此,你最后一个想法是创建一个单独的功能来处理电子邮件发送过程,这也可能会减少响应时间,甚至从关注点的角度来看更有意义。要走这条路,我建议从主功能发送一条PubSub消息,以便第二个功能发送电子邮件。此外,PubSub触发的功能允许配置重试策略,这可能有助于确保邮件将在最终错误的情况下发送。上述问题也提出了这种做法。