【问题标题】:How to fix "Function returned undefined, expected Promise or value"如何修复“函数返回未定义、预期的 Promise 或值”
【发布时间】:2019-10-28 16:58:35
【问题描述】:

我想在 Firebase 函数中完成什么:

  1. 从 Firebase 数据库电子邮件地址读取到批量电子邮件。
  2. 遍历每一个并发送电子邮件。

我在完成我认为的承诺时遇到了问题。这些不需要按顺序运行,我只需要在结束前解决所有的承诺。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const https = require('axios');

exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {

    let emailsToSend = [];

    async function getTests (){
         admin.firestore()
         .collection("tests")
         .get()
         .then(querySnapshot => {
            querySnapshot.forEach(doc => {
                emailsToSend.push(doc.data())
            });
        })
        .catch(function (error) {
            console.error(error);
        });
    }

    async function send (address){
        let body = { 
             //MANDRILL INFO REMOVED
        };

        let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';

        https.post(endpoint, body)
            .then((result) => {
                console.log('SUCCESS');
            })
            .catch(function (error) {
                console.error(error);
            });
    }

    async function init() {
        await getTests();

        for (const email of emailsToSend) {
            await send(email.address);
        }
    }

    init();

});

【问题讨论】:

  • 您的函数需要返回一个承诺,该承诺会在您的函数中的所有异步工作完成时解决。现在,您的函数没有返回任何内容。
  • 是的@DougStevenson,这就是我的问题中的问题描述。
  • 听起来你明白如何继续。你有什么特别的问题吗?
  • @DougStevenson 如果您愿意提供帮助,请再次阅读该问题 - 我无法确定我在哪里错过了 Promise 回报和解决方案。如果您只是来这里钓鱼,请查找另一个帖子。
  • 我只是想确保您理解错误消息的含义。您应该研究使用 Promise.all() 创建一个新的 Promise 来解决或拒绝您正在使用的所有其他 Promise

标签: javascript node.js firebase promise google-cloud-functions


【解决方案1】:

所以你快到了。问题是你没有返回任何东西。你应该通过这样做来解决它:

返回承诺

// code ...

exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
    // code

    return init();
}

使用异步

// code ...

exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(async () => {
    // code

    await init();
}

注意:异步函数总是返回一个 Promise。

建议

在您的代码中,您一次发送一封电子邮件。 await send(email.address);这行代码等到邮件发送完毕,再发送下一封,效率不高。

我的建议是同时发送所有电子邮件并返回一个承诺,该承诺会在每封电子邮件发送时解决。应该是这样的:

//change this 
for (const email of emailsToSend) {
  await send(email.address);
}

// --------------into this--------------------------------

//This is an array of promises
const promises = emailsToSend.map(email => {
    return send(email.address);
});

await Promise.all(promises);

希望有帮助:)

【讨论】:

    【解决方案2】:

    试试这个:

    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp();
    const https = require('axios');
    
    exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
    
        let emailsToSend = [];
    
        function getTests (){
             return new Promise((resolve, reject) => {
                admin.firestore()
                .collection("tests")
                .get()
                .then(querySnapshot => {
                  querySnapshot.forEach(doc => {
                    emailsToSend.push(doc.data())
                  });
                resolve(emailsToSend);
              })
            .catch(function (error) {
                reject(error)
            });
           });
        }
    
        async function send (address){
            let body = { 
                 //MANDRILL INFO REMOVED
            };
    
            let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';
    
            https.post(endpoint, body)
                .then((result) => {
                    console.log('SUCCESS');
                })
                .catch(function (error) {
                    console.error(error);
                });
        }
    
        async function init() {
            const emailsToSend = await getTests();
    
            for (const email of emailsToSend) {
                await send(email.address);
            }
        }
    
        init();
    
    });
    

    也许对你有帮助。

    【讨论】:

    • 这无济于事。该函数需要返回一个在所有异步工作完成时解析的承诺。现在,它什么也没返回。
    • 控制台 emailsToSend 来自 getTests 函数的值并查看值是否存在
    【解决方案3】:

    您的函数缺少 return 语句。 return https.post(...

    【讨论】:

    • 是的@andy-lamb,这就是我的问题中的问题描述
    • @ChefBrian 所以......您知道错误是由于您缺少返回语句引起的。那么当你尝试添加这些 return 语句时,发生了什么?为什么这没有解决问题?是否发生了另一个错误?那是什么?
    猜你喜欢
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    • 2018-12-05
    • 2020-03-09
    • 1970-01-01
    • 2019-08-06
    • 2019-11-18
    • 2018-06-12
    相关资源
    最近更新 更多