![](/img/trans.png)
[英]firebase transaction on lower node - Maximum call stack size exceeded
[英]Nodejs Firebase Transaction - Maximum call stack size exceeded
我有一个云 function,它使用事务来更新游戏中的玩家。 当 /players 为 null 时,我试图返回 Map,但我得到“超出最大调用堆栈大小”。
这是我的云 function:
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
}
});
}
});
});
这是堆栈跟踪:
addUserToGame
Function execution took 1423 ms, finished with status code: 500
at /workspace/node_modules/lodash/lodash.js:13401:38
at encode (/workspace/node_modules/firebase-functions/lib/providers/https.js:179:18)
at Function.mapValues (/workspace/node_modules/lodash/lodash.js:13400:7)
at baseForOwn (/workspace/node_modules/lodash/lodash.js:2990:24)
at /workspace/node_modules/lodash/lodash.js:4900:21
at keys (/workspace/node_modules/lodash/lodash.js:13307:14)
at isArrayLike (/workspace/node_modules/lodash/lodash.js:11333:58)
at isFunction (/workspace/node_modules/lodash/lodash.js:11653:17)
at baseGetTag (/workspace/node_modules/lodash/lodash.js:3067:51)
at Object (<anonymous>)
Unhandled error RangeError: Maximum call stack size exceeded
如何将 map 设置为/players
节点?
代码存在不止一个问题,正如@Renaud 指出的那样,我已将“一次”回调更改为使用 Promise 版本。 我在交易中发回数据时也遇到了问题。 我发送的数据使用的是复杂的 JS 对象,例如 Map(),但经过一番努力(使用语法),我将其更改为普通的 JS object(类似 json 的结构)。 请在下面查看我的更改:
if (t === null) {
return [{ [uid]: { "status": 1 } }]; // if null, create an array and add an object to it
} else {
let playersData = t;
if (playersData.size >= max_players) { // rechecking
return;
} else { // if not null create an object and add to the existing array
playersData.push({
[uid]: {
"status": 1
}
});
return playersData;
}
}
您的问题很可能来自您返回复杂 JavaScript object 的事实,请参阅https://stackoverflow.com/a/525697283/
In addition , note that you should use the promise version of the once()
method, since, in a Callable Cloud Function you must return a promise that resolves with the data object to send back to the client.
而不是做
return gameIDRef.once("value", function (snapshot) {...});
做
return gameIDRef.once("value").then(snapshot => {...});
有了这个,您将能够正确构建要返回的promise 链。 此外,在处理围绕players
价值的不同情况时,而不是返回将在 .then .then((result) => {...})
块中处理的 JavaScript 对象(这不是必需的,也不是真正合乎逻辑的),抛出将在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);
}
});
});
有关如何处理 Callable Cloud Function 中的错误的更多详细信息,请参阅此处。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.