Ожидание значения моментального снимка внутри карты в облачных функциях Firebase

#node.js #firebase #firebase-realtime-database #google-cloud-functions

#node.js #firebase #firebase-база данных в реальном времени #google-cloud-функции

Вопрос:

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

 const functions = require('firebase-functions');
const cors = require('cors')({
    origin: true
});
const admin = require('firebase-admin');
var request = require('request');
admin.initializeApp();
exports.GeraPagSeguro = functions.https.onRequest((req, res) => {
    cors(req, res, () => {
            if (req.method === 'POST') {
                var xml;
                req.body.map((product) => {
                    admin.database().ref(product.refitem).once('value', (snapshot) => {
                        const value = snapshot.val();
                        const price = value.price;
                        xml  = price;
                        //rest of code building the xml i want
                    })
                })
                //rest of code sending the xml via POST to other server
            })
    })
})
  

Проблема в том, что остальная часть кода не wait выполняет все обещания map .

Комментарии:

1. Я так не думаю, я вроде как новичок в node.js и firebase, req.body — это просто обычный объект javascript

2. Мой плохой, я принял это за что-то другое, ознакомьтесь с моим ответом

Ответ №1:

Чтобы дождаться завершения нескольких асинхронных операций, используйте Promise.all() :

 var xml;
var promises = [];
req.body.map((product) => {
    promises.push(admin.database().ref(product.refitem).once('value', (snapshot) => {
        const value = snapshot.val();
        const price = value.price;
        return price;
    })
})
Promise.all(promises).then((prices) => {
    prices.forEach((price) => {
        ...
    });
    //rest of code sending the xml via POST to other server
});
  

Комментарии:

1. Когда я пытаюсь развернуть функцию, я получаю сообщение об ошибке Parsing error: Unexpected token Promise в этой строке let prices = await Promise.all(promises)

2. Интересно. Возможно, вы захотите попробовать это с Promise.all(promises).then(prices => {}); вместо этого.

3. @FrankvanPuffelen по умолчанию асинхронные функции не включены в настройках Firebase functions, вы должны указать некоторые вещи в файле конфигурации, чтобы заставить его работать. Смотрите мой ответ

4. Использование Promise.all(promises).then(prices => {}); сработало, спасибо

5. ОК. Обновлено, чтобы отразить это. Возможно, вы не можете использовать await на верхнем уровне или вам не хватало async аннотации к самому объявлению функции. Честно говоря: я использую Promise.then() еще больше, поэтому не полностью привык к async / await облачным функциям.

Ответ №2:

Поскольку функция базы данных firebase возвращает Promise , вы можете превратить свою функцию в асинхронную функцию и вызвать await ее. Вот так:

 exports.GeraPagSeguro = functions.https.onRequest(async (req, res) => {
    cors(req, res, () => {
            if (req.method === 'POST') {
                var xml;
                req.body.map((product) => {
                    const snapshot = await admin.database().ref(product.refitem).once('value')
                    const value = snapshot.val();
                    const price = value.price;
                    xml  = price;
                    //rest of code building the xml i want
                })
                //rest of code sending the xml via POST to other server
            })
    })
})
  

Затем вы можете выполнить другой код, как будто они «ждали» операции firebase


Примечание: Асинхронные функции не включены в настройках Firebase functions по умолчанию, вам необходимо указать emcaVersion значение 2017 или 8 (по умолчанию 7) в .eslintrc.json файле, чтобы убедиться, что связанные с асинхронностью функции работают. Это должно выглядеть так:

 {
    "parserOptions": {
        "ecmaVersion": 2017 //or 8
    }
}
  

Кроме того, вам также нужно добавить promise в качестве плагина, вот так:

 "plugins": [
    "promise"
 ]
  

Если у вас есть что-либо в, .eslintrc.json что указывает es6 на использование, измените это на es7 .

Комментарии:

1. Кажется, я не мог использовать это async function , потому что я не использовал ` «engines»: { «node»: «8» }` в моем package-json, но теперь я получаю эту ошибку Parsing error: Unexpected token admin

2. Я также получал эту ошибку раньше, вам нужно иметь "parserOptions": { "ecmaVersion": 2017 } в вашем .eslintrc.json файле, чтобы заставить асинхронную работу

3. также добавьте "plugins": [ "promise" ],

4. мой .eslintrc.json также имеет "plugins": [ "promise" ]

5. кроме того, есть ли у вас что-нибудь вроде env, указывающее es6?