Estoy tratando de realizar algunas tareas de base de datos en tiempo real, que después de completarse, deberían enviar un resultado al cliente para que sepa cuándo terminaron las tareas.
exports.createGame = functions.https.onCall((data, context) => { const gameChosen = data.gameChosen; const adminName = data.adminName; const numberOfRounds = data.numberOfRounds; let gameID = Math.floor(100000 + Math.random() * 900000).toString(); var numberOfQuestions = 0; var questionsPicked = []; getGameQuestions(gameChosen, numberOfRounds).then((questionsPickedArray) => { db.ref(`live-games/${gameChosen}/${gameID}`).set( { playerAdmin: adminName, game: gameChosen, players: [adminName], questions: questionsPickedArray, datetimeCreated: Date.now(), }, (error) => { if (error) { console.log("Data could not be saved." + error); } else { console.log("Data saved successfully."); return { gameChosen: gameChosen, gameAdmin: adminName, questions: questionsPicked, gameID: gameID, }; } } ); }); }); function getGameQuestions(gameChosen, numberOfRounds) { var questionsPicked = []; var numberOfQuestions = 0; return new Promise(function (resolve, reject) { db.ref(`games/${gameChosen}`).once("value", function (snapshot) { val = snapshot.val(); numberOfQuestions = val.questionsAvailable; for (var i = 0; i < numberOfRounds; i++) { let questionNumber = Math.floor(Math.random() * (numberOfQuestions - 0 + 1) + 0); if (!questionsPicked.includes(questionNumber)) { questionsPicked.push(questionNumber); } } resolve(questionsPicked); }); }); } Intenté crear una promesa debido al hecho de que algunas tareas de la base de datos en tiempo real no devuelven una promesa; no estaba seguro de cuál. Según los registros, la función se completó con un código de estado de 200 y luego, un par de segundos después, la base de datos en tiempo real se actualiza con los valores. La base de datos debe actualizarse, el resultado debe enviarse de vuelta al cliente y luego la función debe finalizar. Actualmente está devolviendo NULL al cliente, suponiendo que la función lo devuelva tan pronto como se ejecute.
¿Cómo se realizan las tareas de la base de datos en tiempo real una tras otra de manera eficiente?
Tienes que devolver esa Promesa como se menciona aquí .
Para devolver datos después de una operación asincrónica, devuelva una promesa.
exports.createGame = functions.https.onCall((data, context) => { const gameChosen = data.gameChosen; const adminName = data.adminName; const numberOfRounds = data.numberOfRounds; let gameID = Math.floor(100000 + Math.random() * 900000).toString(); var numberOfQuestions = 0; var questionsPicked = []; getGameQuestions(gameChosen, numberOfRounds).then((questionsPickedArray) => { //Just add a return here return db.ref(`live-games/${gameChosen}/${gameID}`).set( { playerAdmin: adminName, game: gameChosen, players: [adminName], questions: questionsPickedArray, datetimeCreated: Date.now(), }) .catch((error) => { if (error) { console.log("Data could not be saved." + error); } else { console.log("Data saved successfully."); return { gameChosen: gameChosen, gameAdmin: adminName, questions: questionsPicked, gameID: gameID, }; } }) ); }); });Las siguientes modificaciones deberían hacer el truco:
exports.createGame = functions.https.onCall((data, context) => { const gameChosen = data.gameChosen; const adminName = data.adminName; const numberOfRounds = data.numberOfRounds; let gameID = Math.floor(100000 + Math.random() * 900000).toString(); var numberOfQuestions = 0; var questionsPicked = []; return getGameQuestions(gameChosen, numberOfRounds) // We return the Promises chain, see below for more details .then((questionsPickedArray) => { return db.ref(`live-games/${gameChosen}/${gameID}`).set( { playerAdmin: adminName, game: gameChosen, players: [adminName], questions: questionsPickedArray, datetimeCreated: Date.now(), }) }) .then(() => { return { gameChosen: gameChosen, gameAdmin: adminName, questions: questionsPicked, gameID: gameID, }; }) .catch((error) => { // See https://firebase.google.com/docs/functions/callable#handle_errors throw new functions.https.HttpsError(...); }); }); function getGameQuestions(gameChosen, numberOfRounds) { var questionsPicked = []; var numberOfQuestions = 0; return db.ref(`games/${gameChosen}`).once("value") // Here too, we return the Promises chain .then(snapshot => { val = snapshot.val(); numberOfQuestions = val.questionsAvailable; for (var i = 0; i < numberOfRounds; i++) { let questionNumber = Math.floor(Math.random() * (numberOfQuestions - 0 + 1) + 0); if (!questionsPicked.includes(questionNumber)) { questionsPicked.push(questionNumber); } } return questionsPicked; }); } Por lo tanto, debe encadenar las Promesas y devolver el resultado al cliente como se muestra arriba: como se explica en el documento "los datos devueltos por la promesa se devuelven al cliente" (que es el caso si devolvemos la cadena de Promesas) y los datos serán un objeto/valor que se puede codificar en JSON (que es el caso del { gameChosen: gameChosen, gameAdmin: adminName, ...} ).
Para la función getGameQuestions() , dado que el método once() devuelve una Promesa, no necesita encapsularla en una Promesa. Nuevamente, simplemente devuelva la cadena de promesas compuesta por once().then(...) .