как использовать облачные функции Firebase с обещаниями и forEach? - PullRequest
0 голосов
/ 01 мая 2018

Я пытаюсь сделать две вещи здесь. 1) Отправьте уведомление всем сотрудникам. 2) Скопировать конкретную ссылку в ID сотрудника исх. если не существует специальных ссылок, я скопирую общие ссылки Программа работает без ошибок. Infact его идеально. Но иногда я получаю сообщение об ошибке тайм-аута с частью кода уведомлений.

Ошибка: тайм-аут сети fcm.googleapis.com. Пожалуйста, попробуйте еще раз.

Код, который копирует одну ссылку на другую, всегда работает, никогда не получал там ошибки. Я чувствую, что ошибка связана с неправильной обработкой обещаний с forEach. Не могли бы вы помочь мне безошибочно выполнить этот код, правильно разместив Обещания?

exports.myFunc = functions.https.onRequest( (request, response) => {

admin.database().ref('/Employees').once('value').then(function(snap) {
    snap.forEach(function (snapshot) {
        var obj = snapshot.val();

        if(obj.department){//only go ahead if dept is present
            console.log(' : ' + obj.department);
            var id, tkid, dept;
            id = obj.empId; tkid = obj.tokenId; dept = obj.department;

            var welcomeStr="hello! Welcom to our Department";

            //================================================================notifications
            var payload = {
                data: {
                  greeting: welcomeStr,
                  to_who: id
                }
              };
                    admin.messaging().sendToDevice(tkid,payload)
                    .then(function(response){
                        console.log("Successfully sent message: ", response);
                    })
                    .catch(function(error){
                            console.log("Error sending message: ", error);
                    })
            //===================================================Ref copying

            var destinationRef = admin.database().ref('/Employees/' + id);//final destination
            var option2Ref = admin.database().ref('/Company/General');//when special doesnt exist
            var option1Ref = admin.database().ref('/Company/Special');//if special exists

            option1.once('value', function(snapshot1){
                if (snapshot1.exists()){//copy from straing from option11 to Employees/id
                    option1.once('value', function(snap)  {
                        destinationRef.set( snap.val(), function(error) {
                            if( error && typeof(console) !== 'undefined' && console.error ) {  console.error(error); }

                            console.log('DONE ....  ' + id);
                        });
                    });
                }

                else{//we need to copy from option2 to Employees/id
                    option2Ref.once('value', function(snap)  {
                        newRef.set( snap.val(), function(error) {
                            if( error && typeof(console) !== 'undefined' && console.error ) {  console.error(error); }

                            console.log('DONE .... ' + id);
                        });
                    });
                }

            });
        }
        else{
            console.log('No Department: ' + obj.dept);
            return;
        }
    });

 });


response.send("WOKAY!");
});

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Чтобы добавить один очень важный шаг в ответ @ChaseMoskal. Для тех, кто использует TypeScript с Firebase, поскольку сервер Firebase не запускает v8 + в NodeJs, велика вероятность того, что вы можете получить эту ошибку:

«Ошибка типа: snapshots.map не является функцией» ... в строке: await Promise.all (snapshots.map (handleSnapshot)).

Это вызывает в вашем файле tsconfig.json "lib": ["es6"] . В этом случае просто добавьте этот небольшой фрагмент к принятому ответу, чтобы получить Firebase Datasnapshot в массив, который можно использовать с .map (...)

Более длинная версия:

exports.myFunc = functions.https.onRequest(async(request, response) => {
const snapshots = await admin.database().ref('/Employees').once('value')

    var data_snap_arr = [];
        snapshots.forEach(function(child_Snapshot) {
            var stuff = child_Snapshot.val();
            stuff.key = child_Snapshot.key;
            data_snap_arr.push(stuff);

await Promise.all(data_snap_arr.map(handleSnapshot))
response.send("WOKAY!")
})

Укороченная версия:

exports.myFunc = functions.https.onRequest(async(request, response) => {
const snapshots = await admin.database().ref('/Employees').once('value')

   let data_snap_arr = Object.keys(snapshots.val() || {}) .map(k => snapshots.val()[k]);

await Promise.all(data_snap_arr.map(handleSnapshot))
response.send("WOKAY!")
})
0 голосов
/ 01 мая 2018

здесь я переписал ваш код в надежде очистить сложные цепочки обещаний

пропущенные обещания - одна из самых распространенных и трудных проблем для отладки, я видел свою справедливую долю

важные изменения в вашем коде:

  1. современный async синтаксис

    • чтобы обещания были чище для организации
  2. используйте Promise.all вместо forEach

    • таким образом, каждое обещание ожидается, не будучи забытым
    • (надеюсь) все обещания возвращаются должным образом
    • все операции моментального снимка выполняются одновременно, и обработчик onRequest должен дождаться завершения всех операций, прежде чем завершить
  3. с использованием обещаний для once и set вместо обратных вызовов

    • Я не совсем уверен, что это за библиотеки
    • похоже, они принимают использование на основе обещаний
    • поэтому я исключил использование обратного вызова в пользу обещаний
  4. пожалуйста, ознакомьтесь с отметкой TODO

    • не совсем уверен, что предназначено для этого блока, так что обязательно исправьте это

async function handleSnapshot(snapshot) {
  const {empId, tokenId, department} = snapshot.val()

  // only go ahead if dept is present
  if (!department) throw new Error("no department")
  console.log("department:", department)

  //================================================================notifications
  const payload = {
    data: {
      greeting: "Hello! Welcome to our Department",
      to_who: empId
    }
  }
  const response = await admin.messaging().sendToDevice(tokenId, payload)
  console.log("successfully sent message", response)
  //===================================================Ref copying

  const destinationRef = admin.database().ref('/Employees/' + empId) // final destination
  const option2Ref = admin.database().ref('/Company/General') // when special doesnt exist
  const option1Ref = admin.database().ref('/Company/Special') // if special exists

  const snapshot1 = await option1Ref.once("value")

  // copy from string from option1 to Employees/id
  if (snapshot1.exists()) { 
    await destinationRef.set(snapshot1.val())
    console.log("DONE1...", empId)
  }

  // TODO review this block
  // we need to copy from option2 to Employees/id
  else {
    const snapshot2 = await option2Ref.once("value")
    await destinationRef.set(snapshot2.val())
    console.log("DONE2...", empId)
  }
}

exports.myFunc = functions.https.onRequest(async(request, response) => {
  const snapshots = await admin.database().ref('/Employees').once('value')
  await Promise.all(snapshots.map(handleSnapshot))
  response.send("WOKAY!")
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...