Возникла проблема с моим облачным сервисом Google - PullRequest
0 голосов
/ 03 мая 2019

У меня есть http-триггер в облачных функциях, который работает, однако я получаю некоторые журналы, возвращающиеся в странном порядке. Я уверен, что не выполнил обещания правильно.

вот код:

exports.createGame = functions.https.onRequest((req, res) => {
    return cors(req, res, () => {

        // Check for POST request
        if (req.method !== "POST") {
            res.status(400).send('Please send a POST request');
            return;
        }
        const createGame = admin.firestore().collection('games')

        generatePin() 

        function generatePin() {
            ...pin generating code goes here...

            addGame(newGidToString)
        }

        function addGame(newGidToString) {
            var getGame = admin.firestore().collection('games')
            getGame = getGame.where('gid', '==', newGidToString)
            getGame.get().then(snapshot => {
                if (snapshot.empty) {

                    console.log('BODY ', req.body)

                    const promises = [];

                    const gameTitle = req.body.gametitle
                    const targetGID = req.body.target
                    const numPlayers = req.body.playercount.toString()

                    const newGID = newGidToString
                    const collections = ['games', 'clues', 'detours', 'messages', 'questions', 'tagstate']
                    collections.forEach(function (element) {
                        console.log('start loop', element)
                        let elementsRef = admin.firestore().collection(element)
                        elementsRef = elementsRef.where('gid', '==', targetGID)
                        elementsRef.get().then(snapshot => {
                            var batch = admin.firestore().batch()
                            snapshot.forEach(function (doc) {
                                // change the gid to the new game gid
                                let data = doc.data()
                                data.gid = newGID

                                if(data.template){
                                    data.template = false
                                }

                                if(!data.parent) {
                                    data.parent = targetGID
                                }

                                if (!data.playercount) {
                                    data.playercount = numPlayers
                                }

                                if (data.gametitle) {
                                    data.gametitle = gameTitle
                                }

                                let elementRef = admin.firestore().collection(element).doc()
                                batch.set(elementRef, data)
                            })
                            batch.commit().then(data => {
                                console.log('complete batch ', element)
                            })
                        })
                    })
                    res.send({ status: 200, message: 'Game: added.', pin: newGID})
                    console.log('completed');
                } else {
                    console.log('found a match ', snapshot)
                    // re-run the generator for a new pin
                    generatePin()
                }
            })
        }
    })

})

Вот снимок экрана журналов консоли.

enter image description here

Обратите внимание на порядок журналов. Казалось бы логичным, что completed придет в конце цикла.

Любая помощь приветствуется.

UPDATE:

function addGame(newGidToString) {
            var getGame = admin.firestore().collection('games')
            getGame = getGame.where('gid', '==', newGidToString)
            getGame.get().then(snapshot => {
                if (snapshot.empty) {

                    console.log('BODY ', req.body)

                    const promises = [];

                    const gameTitle = req.body.gametitle
                    const targetGID = req.body.target
                    const numPlayers = req.body.playercount.toString()

                    const newGID = newGidToString

                    const collections = ['games', 'clues', 'detours', 'messages', 'questions', 'tagstate']
                    collections.forEach(function (element) {

                        console.log('start loop', element)

                        let elementsRef = admin.firestore().collection(element)
                        elementsRef = elementsRef.where('gid', '==', targetGID)
                        // elementsRef.get().then(snapshot => {

                        const promGet = elementsRef.get();  //lets get our promise
                        promises.push(promGet);             //place into an array
                            promGet.then(snapshot => {  //we can now continue as before

                            var batch = admin.firestore().batch()

                            snapshot.forEach(function (doc) {
                                // change the gid to the new game gid
                                let data = doc.data()
                                data.gid = newGID

                                if(data.template){
                                    data.template = false
                                }

                                if(!data.parent) {
                                    data.parent = targetGID
                                }

                                if (!data.playercount) {
                                    data.playercount = numPlayers
                                }

                                if (data.gametitle) {
                                    data.gametitle = gameTitle
                                }

                                let elementRef = admin.firestore().collection(element).doc()
                                batch.set(elementRef, data)
                            })
                            batch.commit().then(data => {
                                console.log('complete batch ', element)
                            })

                        })
                    })
                    Promise.all(promises).then(() => {
                        res.send({ status: 200, message: 'Game: added.', pin: newGID })
                        console.log('completed');
                    });
                    // res.send({ status: 200, message: 'Game: added.', pin: newGID})
                    // console.log('completed');
                } else {
                    console.log('found a match ', snapshot)
                    // re-run the generator for a new pin
                    generatePin()
                }
            })
        }

ВТОРОЕ ОБНОВЛЕНИЕ: (основываясь на ответе Кейта)

function addGame(newGidToString) {
            var getGame = admin.firestore().collection('games')
            getGame = getGame.where('gid', '==', newGidToString)
            getGame.get().then(snapshot => {
                if (snapshot.empty) {

                    console.log('BODY ', req.body)

                    const gameTitle = req.body.gametitle
                    const targetGID = req.body.target
                    const numPlayers = req.body.playercount.toString()

                    const newGID = newGidToString

                    const promises = [];

                    const collections = ['games', 'clues', 'detours', 'messages', 'questions', 'tagstate']
                    collections.forEach(function (element) {

                        console.log('start loop', element)

                        let elementsRef = admin.firestore().collection(element)
                        elementsRef = elementsRef.where('gid', '==', targetGID)

                        const getPromise = elementsRef.get();  //lets get our promise
                        promises.push(getPromise);             //place into an array
                        getPromise.then(snapshot => {  //we can now continue as before

                            var batch = admin.firestore().batch()

                            snapshot.forEach(function (doc) {
                                // change the gid to the new game gid
                                let data = doc.data()
                                data.gid = newGID

                                if(data.template){
                                    data.template = false
                                }

                                if(!data.parent) {
                                    data.parent = targetGID
                                }

                                if (!data.playercount) {
                                    data.playercount = numPlayers
                                }

                                if (data.gametitle) {
                                    data.gametitle = gameTitle
                                }

                                let elementRef = admin.firestore().collection(element).doc()
                                batch.set(elementRef, data)
                            })
                            batch.commit()
                        })
                    })
                    Promise.all(promises).then(() => {
                        res.send({ status: 200, message: 'Game: added.', pin: newGID })
                        console.log('completed from promise');
                    });
                } else {
                    console.log('found a match ', snapshot)
                    // re-run the generator for a new pin
                    generatePin()
                }
            })
        }

1 Ответ

2 голосов
/ 03 мая 2019

При зацикливании с обещаниями нужно помнить одну вещь: если вы выполните forEach, это не будет ждать.

Похоже, что ОП хочет сделать до того, как он доберется до завершения и отправит повтор, хочет убедиться, что все обещания были выполнены.

Promise.all https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all, это именно то, что он делает.

Таким образом, каждый раз, когда вы создаете обещание, если вы помещаете его в массив, мы можем позже использовать Promise.all, чтобы убедиться, что все обещания выполнены.

Так что если мы заменим

elementsRef.get().then(snapshot => {

с

const promGet = elementsRef.get();  //lets get our promise
promises.push(promGet);             //place into an array
promGet.then(snapshot => {          //we can now continue as before

Ваше обещание теперь сохраняется на потом, поэтому Promise.all может проверить, что все выполнено. Вы можете сделать это в одну строку, но я чувствую, что легче увидеть, что происходит таким образом. например ->

promises.push(promGet.then(snapshot => {

Наконец, теперь у нас есть наш массив обещаний, прежде чем мы сделаем res.send, давайте удостоверимся, что они все выполнили.

Promise.all(promises).then(() => {
  res.send({ status: 200, message: 'Game: added.', pin: newGID})
  console.log('completed');
});

Одна вещь, которую следует иметь в виду при использовании Обещаний таким образом, это то, что у вас происходит довольно много вещей одновременно, иногда это может быть проблемой, например. подключение к какой-либо службе может наложить ограничения на количество одновременных подключений и т. д. Так что в этих случаях это может быть идея делать что-то последовательно или сочетать оба варианта. Есть даже библиотеки, которые могут выполнять параллелизм, например. Выполняйте только X обещаний за раз.

И, наконец, если вы можете использовать async / await, я бы посоветовал использовать их, поскольку это делает Promises намного приятнее в работе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...