Javascript Nodejs Firebase事务-超过最大调用堆栈大小
我有一个云函数,它使用事务更新游戏中的玩家。当/players为空时,我试图返回一个映射,但得到“超出了最大调用堆栈大小” 以下是我的云功能:Javascript Nodejs Firebase事务-超过最大调用堆栈大小,javascript,node.js,firebase,firebase-realtime-database,google-cloud-functions,Javascript,Node.js,Firebase,Firebase Realtime Database,Google Cloud Functions,我有一个云函数,它使用事务更新游戏中的玩家。当/players为空时,我试图返回一个映射,但得到“超出了最大调用堆栈大小” 以下是我的云功能: export const addUserToGame = functions.https.onCall((data, context) => { // Expected inputs - game_id(from data) and UID(from context) if (context.auth == null) {
export const addUserToGame = functions.https.onCall((data, context) => {
// Expected inputs - game_id(from data) and UID(from context)
if (context.auth == null) {
return {
"status": 403,
"message": "You are not authorized to access this feature"
};
}
const uid = context.auth.uid;
const game_id = data.game_id;
let gameIDRef = gamesRef.child(game_id);
return gameIDRef.once("value", function (snapshot) {
let players: Map<String, Number> = snapshot.child("players").val();
let max_players: Number = snapshot.child("max_players").val();
if (players != null && players.has(uid)) {
return {
"status": 403,
"message": "Player already in the game"
}
} else if (players != null && players.size >= max_players) {
return {
"status": 403,
"message": "Game is already full"
}
} else {
let playersNodeRef = gamesRef.child(game_id).child("players");
return playersNodeRef.transaction(t => {
if (t === null) {
return new Map<String, Number>().set(uid, 1);//trying to set a map with the player data, when the /players is null
} else {
let playersData: Map<String, Number> = t;
if (playersData.size >= max_players) { // rechecking
return;
} else {
playersData.set(uid, 1);
return playersData;
}
}
}).then(result => {
if (result.committed) { // if true there is a commit and the transaction went through
return {
"status": 200,
"message": "User added to game successfully"
}
} else {
return {
"status": 403,
"message": "Unable to add user at this time. Please try again"
}
}
}).catch(error => {
return {
"status": 403,
"message": error
}
});
}
});
});
您的问题很可能是由于返回了一个复杂的JavaScript对象,请参阅 此外请注意,您应该使用该方法的promise版本,因为在可调用的云函数中,您必须返回与要发送回客户端的数据对象解析的promise 而不是做
return gameIDRef.once("value", function (snapshot) {...});
做
有了它,您将能够正确构建要返回的。另外,在处理players
值周围的不同情况时,不要返回将在中处理的JavaScript对象。然后((result)=>{…})
块(这不是必需的,也不是真正合乎逻辑的),抛出将在catch()
块中处理的错误
大致如下:
export const addUserToGame = functions.https.onCall((data, context) => {
// Expected inputs - game_id(from data) and UID(from context)
if (context.auth == null) {
return {
status: 403,
message: 'You are not authorized to access this feature',
};
// IMHO better to do throw new functions.https.HttpsError('...', ...);
}
const uid = context.auth.uid;
const game_id = data.game_id;
let gameIDRef = gamesRef.child(game_id);
return gameIDRef
.once('value')
.then((snapshot) => {
let players: Map<String, Number> = snapshot.child('players').val();
let max_players: Number = snapshot.child('max_players').val();
if (players != null && players.has(uid)) {
throw new Error('Player already in the game');
} else if (players != null && players.size >= max_players) {
throw new Error('Game is already full');
} else {
let playersNodeRef = gamesRef.child(game_id).child('players');
return playersNodeRef.transaction((t) => {
if (t === null) {
return new Map<String, Number>().set(uid, 1); //trying to set a map with the player data, when the /players is null
} else {
let playersData: Map<String, Number> = t;
if (playersData.size >= max_players) {
// rechecking
return;
} else {
playersData.set(uid, 1);
return playersData;
}
}
});
}
})
.then((result) => {
if (result.committed) {
// if true there is a commit and the transaction went through
return {
status: 200,
message: 'User added to game successfully',
};
} else {
// probably throw an error here
return {
status: 403,
message: 'Unable to add user at this time. Please try again',
};
}
})
.catch((error) => {
if (error.message === 'Player already in the game') {
throw new functions.https.HttpsError('...', error.message);
} else if (error.message === 'Game is already full') {
throw new functions.https.HttpsError('...', error.message);
} else {
throw new functions.https.HttpsError('internal', error.message);
}
});
});
export const addUserToGame=functions.https.onCall((数据,上下文)=>{
//预期输入-游戏id(来自数据)和UID(来自上下文)
if(context.auth==null){
返回{
现状:403,
消息:“您无权访问此功能”,
};
//我最好抛出新函数。https.HttpsError(“…”,…);
}
const uid=context.auth.uid;
const game\u id=data.game\u id;
让gameIDRef=gamesRef.child(游戏id);
返回gameIDRef
.once('值')
。然后((快照)=>{
让玩家:Map=snapshot.child('players').val();
让max_players:Number=snapshot.child('max_players').val();
if(players!=null&&players.has(uid)){
抛出新错误(“玩家已在游戏中”);
}else if(players!=null&&players.size>=max\u players){
抛出新错误(“游戏已满”);
}否则{
let playersNodeRef=gamesRef.child(game_id).child('players');
return playersNodeRef.transaction((t)=>{
如果(t==null){
return new Map().set(uid,1);//当/players为空时,尝试使用播放器数据设置地图
}否则{
让playersData:Map=t;
如果(playersData.size>=最大玩家数){
//复查
返回;
}否则{
playersData.set(uid,1);
返回playersData;
}
}
});
}
})
。然后((结果)=>{
if(result.committed){
//如果为true,则存在提交,并且事务已通过
返回{
现状:200,
消息:“用户已成功添加到游戏”,
};
}否则{
//可能会在这里抛出一个错误
返回{
现状:403,
消息:“此时无法添加用户。请重试”,
};
}
})
.catch((错误)=>{
如果(error.message==='玩家已在游戏中'){
抛出新函数.https.HttpsError(“…”,error.message);
}else if(error.message==='游戏已满'){
抛出新函数.https.HttpsError(“…”,error.message);
}否则{
抛出新函数.https.HttpsError('internal',error.message);
}
});
});
有关如何处理可调用云函数中的错误的更多详细信息,请参阅。您的问题很可能来自返回复杂JavaScript对象的事实,请参阅 此外请注意,您应该使用该方法的promise版本,因为在可调用的云函数中,您必须返回与要发送回客户端的数据对象解析的promise 而不是做
return gameIDRef.once("value", function (snapshot) {...});
做
有了它,您将能够正确构建要返回的。另外,在处理players
值周围的不同情况时,不要返回将在中处理的JavaScript对象。然后((result)=>{…})
块(这不是必需的,也不是真正合乎逻辑的),抛出将在catch()
块中处理的错误
大致如下:
export const addUserToGame = functions.https.onCall((data, context) => {
// Expected inputs - game_id(from data) and UID(from context)
if (context.auth == null) {
return {
status: 403,
message: 'You are not authorized to access this feature',
};
// IMHO better to do throw new functions.https.HttpsError('...', ...);
}
const uid = context.auth.uid;
const game_id = data.game_id;
let gameIDRef = gamesRef.child(game_id);
return gameIDRef
.once('value')
.then((snapshot) => {
let players: Map<String, Number> = snapshot.child('players').val();
let max_players: Number = snapshot.child('max_players').val();
if (players != null && players.has(uid)) {
throw new Error('Player already in the game');
} else if (players != null && players.size >= max_players) {
throw new Error('Game is already full');
} else {
let playersNodeRef = gamesRef.child(game_id).child('players');
return playersNodeRef.transaction((t) => {
if (t === null) {
return new Map<String, Number>().set(uid, 1); //trying to set a map with the player data, when the /players is null
} else {
let playersData: Map<String, Number> = t;
if (playersData.size >= max_players) {
// rechecking
return;
} else {
playersData.set(uid, 1);
return playersData;
}
}
});
}
})
.then((result) => {
if (result.committed) {
// if true there is a commit and the transaction went through
return {
status: 200,
message: 'User added to game successfully',
};
} else {
// probably throw an error here
return {
status: 403,
message: 'Unable to add user at this time. Please try again',
};
}
})
.catch((error) => {
if (error.message === 'Player already in the game') {
throw new functions.https.HttpsError('...', error.message);
} else if (error.message === 'Game is already full') {
throw new functions.https.HttpsError('...', error.message);
} else {
throw new functions.https.HttpsError('internal', error.message);
}
});
});
export const addUserToGame=functions.https.onCall((数据,上下文)=>{
//预期输入-游戏id(来自数据)和UID(来自上下文)
if(context.auth==null){
返回{
现状:403,
消息:“您无权访问此功能”,
};
//我最好抛出新函数。https.HttpsError(“…”,…);
}
const uid=context.auth.uid;
const game\u id=data.game\u id;
让gameIDRef=gamesRef.child(游戏id);
返回gameIDRef
.once('值')
。然后((快照)=>{
让玩家:Map=snapshot.child('players').val();
让max_players:Number=snapshot.child('max_players').val();
if(players!=null&&players.has(uid)){
抛出新错误(“玩家已在游戏中”);
}else if(players!=null&&players.size>=max\u players){
抛出新错误(“游戏已满”);
}否则{
let playersNodeRef=gamesRef.child(game_id).child('players');
return playersNodeRef.transaction((t)=>{
如果(t==null){
return new Map().set(uid,1);//当/players为空时,尝试使用播放器数据设置地图
}否则{
让playersData:Map=t;
如果(playersData.size>=最大玩家数){
//复查
返回;
}否则{
playersData.set(uid,1);
返回playersData;
}
}
});
}
})
。然后((结果)=>{
if(result.committed){
//如果为true,则存在提交,并且事务已通过
返回{
现状:200,
消息:“用户已成功添加到游戏”,
};
}否则{
//可能会在这里抛出一个错误
返回{
export const addUserToGame = functions.https.onCall((data, context) => {
// Expected inputs - game_id(from data) and UID(from context)
if (context.auth == null) {
return {
status: 403,
message: 'You are not authorized to access this feature',
};
// IMHO better to do throw new functions.https.HttpsError('...', ...);
}
const uid = context.auth.uid;
const game_id = data.game_id;
let gameIDRef = gamesRef.child(game_id);
return gameIDRef
.once('value')
.then((snapshot) => {
let players: Map<String, Number> = snapshot.child('players').val();
let max_players: Number = snapshot.child('max_players').val();
if (players != null && players.has(uid)) {
throw new Error('Player already in the game');
} else if (players != null && players.size >= max_players) {
throw new Error('Game is already full');
} else {
let playersNodeRef = gamesRef.child(game_id).child('players');
return playersNodeRef.transaction((t) => {
if (t === null) {
return new Map<String, Number>().set(uid, 1); //trying to set a map with the player data, when the /players is null
} else {
let playersData: Map<String, Number> = t;
if (playersData.size >= max_players) {
// rechecking
return;
} else {
playersData.set(uid, 1);
return playersData;
}
}
});
}
})
.then((result) => {
if (result.committed) {
// if true there is a commit and the transaction went through
return {
status: 200,
message: 'User added to game successfully',
};
} else {
// probably throw an error here
return {
status: 403,
message: 'Unable to add user at this time. Please try again',
};
}
})
.catch((error) => {
if (error.message === 'Player already in the game') {
throw new functions.https.HttpsError('...', error.message);
} else if (error.message === 'Game is already full') {
throw new functions.https.HttpsError('...', error.message);
} else {
throw new functions.https.HttpsError('internal', error.message);
}
});
});