Firebase云功能承诺

时间:2018-08-13 17:09:19

标签: javascript firebase google-cloud-functions

我很难让一个承诺链在Firebase云功能中正确流动。它遍历一个ref并返回一系列电子邮件以发送通知。它有一些嵌套的子级,我认为这就是我要出错的地方,但是我似乎找不到错误。

/课程结构

{
  123456id: {
    ..
    members: {
      uidKey: {
        email: some@email.com
      },
      uidKey2: {
        email: another@email.com
      }
    }
   },
   some12345string: {
     // no members here, so skip
   }
}

function.js

exports.reminderEmail = functions.https.onRequest((req, res) => {
  const currentTime = new Date().getTime();
  const future = currentTime + 172800000;
  const emails = [];

  // get the main ref and grab a snapshot
  ref.child('courses/').once('value').then(snap => {
    snap.forEach(child => {
      var el = child.val();

      // check for the 'members' child, skip if absent
      if(el.hasOwnProperty('members')) {

        // open at the ref and get a snapshot
        var membersRef = admin.database().ref('courses/' + child.key + '/members/').once('value').then(childSnap => {
          console.log(childSnap.val())
          childSnap.forEach(member => {
            var email = member.val().email;
            console.log(email); // logs fine, but because it's async, after the .then() below for some reason
            emails.push(email);
          })
        })
      }
    })
    return emails  // the array
  })
  .then(emails => {
    console.log('Sending to: ' + emails.join());
    const mailOpts = {
      from: 'me@email.com',
      bcc: emails.join(),
      subject: 'Upcoming Registrations',
      text: 'Something about registering here.'
    }
    return mailTransport.sendMail(mailOpts).then(() => {
      res.send('Email sent')
    }).catch(error => {
      res.send(error)
    })
  })
})

2 个答案:

答案 0 :(得分:1)

以下应该可以解决问题。

正如道格·史蒂文森(Doug Stevenson)在回答中所解释的那样,Promise.all()方法返回一个单个承诺,当所有承诺由once()方法返回并推送到promises数组时,它就会解析,已解决。

exports.reminderEmail = functions.https.onRequest((req, res) => {
  const currentTime = new Date().getTime();
  const future = currentTime + 172800000;
  const emails = [];

  // get the main ref and grab a snapshot
  return ref.child('courses/').once('value') //Note the return here
  .then(snap => {
    const promises = [];

    snap.forEach(child => {      
      var el = child.val();

      // check for the 'members' child, skip if absent
      if(el.hasOwnProperty('members')) { 
        promises.push(admin.database().ref('courses/' + child.key + '/members/').once('value')); 
      }
    });

    return Promise.all(promises);
  })
  .then(results => {
    const emails = [];

    results.forEach(dataSnapshot => {
       var email = dataSnapshot.val().email;
       emails.push(email);
    });

    console.log('Sending to: ' + emails.join());
    const mailOpts = {
      from: 'me@email.com',
      bcc: emails.join(),
      subject: 'Upcoming Registrations',
      text: 'Something about registering here.'
    }
    return mailTransport.sendMail(mailOpts);
  })
  .then(() => {
      res.send('Email sent')
    })
  .catch(error => { //Move the catch at the end of the promise chain
      res.status(500).send(error)
  });

})

答案 1 :(得分:0)

您应该将诺言放入数组中,并使用Promise.all()等到它们全部完成,而不是处理内联查询中的所有诺言并将电子邮件推送到数组中。然后,迭代快照数组以构建电子邮件数组。

您可能会发现我的有关在Cloud Functions中使用Promise的教程有助于学习某些技术:https://firebase.google.com/docs/functions/video-series/