簡體   English   中英

如何將Firebase雲功能與promises和forEach一起使用?

[英]how to use Firebase Cloud Functions with promises and forEach?

我想在這里做兩件事。 1)向所有員工發送通知。 2)將特定的ref復制到Employees id ref。 如果沒有特殊參考,我將復制一般參考。 該程序運行沒有錯誤。 事實上它是完美的。 但有時我會通知通知代碼部分出現Timed out錯誤。

錯誤:fcm.googleapis.com網絡超時。 請再試一次。

將一個引用復制到另一個引用的代碼始終有效,從未在那里收到過錯誤。 我覺得錯誤是由於沒有正確處理forEach的承諾。 你能用正確放置的Promises來幫助我讓這個代碼完美無缺嗎?

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!");
});

在這里,我重寫了你的代碼,希望能夠清理復雜的承諾鏈

丟失的承諾是調試中最常見和最困難的問題之一,我已經看到了我的公平份額

您的代碼的重要更改:

  1. 現代async語法

    • 這樣的承諾可以更清晰地組織起來
  2. 使用Promise.all而不是forEach

    • 這樣,等待的每一個承諾都不會被遺忘
    • (希望)所有的承諾都能正確歸還
    • 所有快照操作都是並發運行的,onRequest處理程序應該等到它們全部完成才終止
  3. 使用promises onceset而不是回調

    • 我不確定這些庫是什么
    • 看起來他們接受基於承諾的使用
    • 所以我刪除了回調用法,以支持承諾
  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!")
})

為@ChaseMoskal回答添加一個非常重要的步驟。 對於使用TypeScript和Firebase的用戶,由於firebase服務器未在NodeJs中運行v8 +,因此很可能會出現此錯誤:

“TypeError:snapshots.map不是函數”......在線:await Promise.all(snapshots.map(handleSnapshot))。

這在你的tsconfig.json中導致它可能是“lib”:[“es6”] 在這種情況下,只需將此小片段添加到接受的答案中,即可將Firebase數據快照放入可與.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!")
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM