【问题标题】:Function Return Undefined, Expected Promise or Value函数返回未定义、预期的承诺或值
【发布时间】:2020-12-23 08:41:22
【问题描述】:

云功能和承诺的新手。我尝试在不同的位置添加承诺,但仍然在日志中收到消息。首先,我不确定我应该在哪里添加承诺,其次我是否应该什么都不返回。调用 match 后我不需要执行另一个函数(如果条件满足则创建通道)。虽然触发 onCreate 会有多个用户,所以我想确保一次执行一个用户。

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

//every time user added to liveLooking node
exports.command = functions.database
        .ref('liveLooking/{uid}')
        .onCreate((snap, context) => {
    const uid = context.params.uid
    match(uid)
})
function match(uid) {
    let m1uid, m2uid
    admin.database().ref('liveChannels').transaction((data) => {
        //if no existing channels then add user to liveChannels
        if (data === null) {
            console.log(`${uid} waiting for match`)
            return { uid: uid }
        }
        else {
            m1uid = data.uid
            m2uid = uid
            if (m1uid === m2uid) {
                console.log(`$m1uid} tried to match with self!`)
                //match user with liveChannel user
            } else {
                console.log(`matched ${m1uid} with ${m2uid}`)
                createChannel(m1uid, m2uid) 
                return null
            }
        }
    },
    (error, committed, snapshot) => {
        if (error) {
            throw error
        }
        else {
             return {
                committed: committed,
                snapshot: snapshot
            }
        }
    },
    false)
 }

function createChannel(uid1, uid2) {
    // Add channels for each user matched
    const channel_id = uid1+uid2
    console.log(`starting channel ${channel_id} with uid1: ${uid1}, uid2: ${uid2}`)
    const m_state1 = admin.database().ref(`liveUsers/${uid1}`).set({
        channel: channel_id
    })
    const m_state2 = admin.database().ref(`liveUsers/${uid2}`).set({
        channel: channel_id
    })
}

编辑 1 - 我尝试将交易更改为使用 await,因此它只会在交易后更改 userLives 节点。收到这两个警告。 1) 预期在异步函数“匹配”结束时返回一个值。 2) 在 ***return 箭头函数需要一个返回值。如果使用与 self 匹配,我不会尝试更改 LiveChannels 下的任何内容。不知道如何解决该警告。 3) 仍然在日志中返回未定义、预期的承诺或值的函数 - 我认为是命令函数。

async function match(uid) {
  let m1uid, m2uid;
  let createChannel = false
  try {
    const transactionResult = await admin
      .database()
      .ref("liveChannels")
      .transaction(
        (data) => {
             if (data === null) {
                 console.log(`${uid} waiting for match`)
                 return { uid: uid }
             }
             else {
                 m1uid = data.uid
                 m2uid = uid
                 if (m1uid === m2uid) {
                     console.log(`$m1uid} tried to match with self!`)
                     ***return***
                 } else {
                     console.log(`matched ${m1uid} with ${m2uid}`)
                     createChannel = true
                     return {}
                 }
             }
        },
        (error, committed, snapshot) => {
             if (error) {
                 throw error
             }
             else {
                  return {
                     committed: committed,
                     snapshot: snapshot
                 }
             }
        },
        false
      );

    if (transactionResult) {
        if (createChannel) {
            const channel_id = m1uid + m2uid
            console.log(`starting channel ${channel_id} with uid1:    ${m1uid}, uid2: ${m2uid}`)
            const m_state1 = admin.database().ref(`liveUsers/${m1uid}`).set({
                channel: channel_id
            })
            const m_state2 = admin.database().ref(`liveUsers/${m2uid}`).set({
                channel: channel_id
            })
            return Promise.all([m_state1, m_state2])
        }
    }
  } catch (err) {
    throw new Error(err);
  }
}

【问题讨论】:

  • 哪个函数应该返回一个 Promise 但返回 undefined?
  • 不确定我是否需要对 onCreate one 和 match 都做出承诺?

标签: javascript firebase firebase-realtime-database promise google-cloud-functions


【解决方案1】:

您没有正确管理the life cycle of your Cloud Function。您需要等待所有异步任务(即对 Firebase 异步方法的调用)都完成,然后再向平台指示它可以清理该函数。这应该通过返回一个 Promise 来完成,更准确地说,因为您通过返回 promises chain 链接了多个异步方法调用。

然而,你的云函数还有一个问题,就是你写Transaction的方式。事务以原子方式修改您调用事务所在位置(即Reference)的数据。

在您的代码中,您在ref('liveChannels') 上调用事务,但在事务内部,您在其他位置修改数据:ref(`liveUsers/${uid1}`)ref(`liveUsers/${uid2}`)

这不是正确的方法:如果你想将所有这些操作封装在一个事务中,你需要在包含你想要更改的所有节点/位置的数据库节点上调用事务,即一个共同的父/祖先liveChannelsliveUsers/${uid1}liveUsers/${uid2} 的节点。

如果我没有弄错这三个节点的唯一共同父/祖先节点是数据库根节点。在 DB 根节点上调用 Transaction 可能不是一个好主意,特别是如果您有很多用户同时使用您的应用程序。您可能应该调整您的数据模型(数据库结构)以避免这种情况。


还要注意,不要使用Tansaction的onComplete回调来处理它的成功和失败,你应该使用Transaction返回的Promise,以便在Promise链中正确使用它(见第一段)。

【讨论】:

  • 我的编辑是否解决了交易问题?我仍然在编辑部分中列出了上面列出的问题。我认为承诺链文章使用 .then 所以尝试使用 await 代替
猜你喜欢
  • 2019-06-09
  • 2018-06-17
  • 2018-09-03
  • 1970-01-01
  • 2018-12-17
  • 2019-05-11
  • 1970-01-01
  • 2019-09-07
  • 2019-09-15
相关资源
最近更新 更多