Node.js Firebase管理员顺序调用,返回值和承诺

Node.js Firebase管理员顺序调用,返回值和承诺,node.js,firebase,google-cloud-functions,firebase-admin,Node.js,Firebase,Google Cloud Functions,Firebase Admin,0)我有一个HTTP触发器: exports.checkout = functions.https.onRequest((req, res) => { 1) 当用户购买充值包时更新充值事务: admin.database().ref('topupTransaction').push(topUpObject) 2) 获取用户对象(具有帐户余额) 3) 设置新用户对象(具有新帐户余额) 我不知道如何按顺序运行所有这些(1、2、3)并将值返回给客户端(0)。打击不应该包含承诺。这是承诺,但在

0)我有一个HTTP触发器:

exports.checkout = functions.https.onRequest((req, res) => {
1) 当用户购买充值包时更新充值事务:

admin.database().ref('topupTransaction').push(topUpObject)
2) 获取用户对象(具有帐户余额)

3) 设置新用户对象(具有新帐户余额)

我不知道如何按顺序运行所有这些(1、2、3)并将值返回给客户端(0)。打击不应该包含承诺。这是承诺,但在这种情况下如何使用它

点击“避免嵌套承诺”。当我尝试这样做时:

exports.checkout=functions.https.onRequest((req,res)=>{ var nonefromtheclient=req.body.payment\u method\u nonce

  var topUpObject = {
    amount : parseInt(req.query.topUpPackage),
    date : admin.database.ServerValue.TIMESTAMP, // 1525451616097
    user : req.query.userUid
  };

  admin.database().ref('topupTransaction').push(topUpObject)
  .then((topUpResult) => {
    return admin.database().ref('/users/' + userID).once("value");
  }).then((oldUserData)=>{
    return admin.database().ref('/users/' + req.query.userUid).set(topUpObject).then((newUserData)=>{
      return res.send(newUserData.val());
    })
      ;
  }).catch((error) => {
    // Update databse failed (top up transaction)
    console.log('Error sending message:', error);
    return res.status(500).send(error);
  });
更新

使用Promise.all,但部分处理错误:

// Create 2 functions
function asyncFunction1(topUpObject){
    // Push top up object to database
    admin.database().ref('topupTransaction').push(topUpObject)
      .then((response) => {
        // Update databse successful (top up transaction)
        console.log('Top Up transaction created successfully!', topUpObject);
        // return res.redirect(303, response.ref);
        return topUpObject;
      }).catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return error;
      });
}

function asyncFunction2(userID,topUpObject){
    // Get the user account balance
    console.log('Current User ID: ', userID);
    var ref = admin.database().ref('users').child(userID);
    admin.database().ref('/users/' + userID).once("value",snap=> {
      // do some stuff once
      console.log('Current User Data',snap.val());
      console.log('Current User balance',snap.val().accountBalance);
      var userContents = snap.val();
      var currentBalance = userContents.accountBalance;
      var updatedBalance = currentBalance + topUpObject.amount;
      console.log('Updated Balance',updatedBalance);
      userContents.accountBalance = updatedBalance;
      /*Current User Data { 
        accountBalance: 0,
        accountCurrency: 'MYR',
        createdOn: '2018-05-02T20:42:49Z',
        phoneNumber: '+123445555555'
      }
      */
      admin.database().ref('/users/' + userID).set(userContents).then(snapshot => {
        console.log('Updated top up value! for user', topUpObject);
        return res.send(topUpObject.amount);  
      }).catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return error;
      });

    });
}

// app.post("/checkout", function (req, res) {
exports.checkout = functions.https.onRequest((req, res) => {
  var nonceFromTheClient = req.body.payment_method_nonce;
  // Use payment method nonce here

  // Create Transaction
  gateway.transaction.sale({ 
    amount: req.query.topUpPackage,
    paymentMethodNonce: nonceFromTheClient,
    options: {
      submitForSettlement: true
    }
  },(err, result) => { //TODO: What should we pass back here???
    if (err) {
    // If top up error (from braintree)
      console.log(err.stack);
    }else{
    // If top up is successful
      console.log('Result:',result);
      console.log('Top Up Package is: ', req.query.topUpPackage);
      var topUpObject = {
        amount : parseInt(req.query.topUpPackage),
        date : admin.database.ServerValue.TIMESTAMP, // 1525451616097
        user : req.query.userUid
      };
      return Promise.all([asyncFunction1(topUpObject), asyncFunction2(req.query.userUid,topUpObject)]); //TODO: how to pass back res() to client???
    }
    // Return the error as response
    return res.send(err);
  });
});

exports.client_token = functions.https.onRequest((req, res) => {

    // a token needs to be generated on each request
    // so we nest this inside the request handler

    // Need to write a function to return a client token,
    // and return it back by using the res.send command
    console.log('Log customerId',req.query.text);

    gateway.clientToken.generate({
      // customerId: req.query.text
    }, (err, response) => {
      // error handling for connection issues
      if (err) {
        console.log(err.stack);
      }else{
        clientToken = response.clientToken;
        console.log('Log Client token:',clientToken);
        return res.send(clientToken);
      }
      return res.send(err);
    });
    // return null;
});

在我看来,在你的代码中有两件事情需要微调,如下所示

但是,请注意,因为我们不知道topUpObject的来源(以及它是什么),所以要更精确一些有点困难。如果您分享更多细节(完整的云函数代码和数据库结构),我可能会更精确

admin.database().ref('topupTransaction').push(topUpObject)
    .then(topUpResult => {
        return admin.database().ref('/users/' + userID).once("value");
    })
    .then(oldUserData => {
         return admin.database().ref('/users/' + req.query.userUid).set(topUpObject);  
         //Set returns a non-null firebase.Promise containing void
    })
    .then(() => {  //so I don't think you can get the newUserData here
        //return res.send(newUserData.val());  <- and therefore you cannot do that here
        //But if I understand well you want to send back to the user the topUpObject, so do as follows:
        return res.status(200).send(topUpObject);  //<- note the addition of status(200) here
    })
    .catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return res.status(500).send(error);
});
admin.database().ref('topupTransaction').push(topUpObject)
。然后(topUpResult=>{
返回admin.database().ref('/users/'+userID).once(“value”);
})
。然后(oldUserData=>{
返回admin.database().ref('/users/'+req.query.userUid).set(topUpObject);
//Set返回一个非null的firebase.Promise,其中包含void
})
.然后(()=>{//所以我认为你不能在这里获得新的用户数据

//return res.send(newUserData.val());Hi@Renaud Tarnec,在客户端,用户正在购买一个充值包,例如$50。在firebase后端,它需要做3件事…第一件是创建事务,第二件是获取当前用户数据(带有帐户余额)并在当前帐户余额中添加50美元,第三个是用新余额更新用户数据。你知道如何使用Promise.all实现这一点吗?我使用braintree sdkNot确定你必须使用Promise.all。你能分享你的全部代码吗?更新了代码。请帮助:D不熟悉Promise.all。我想(再次,IMHO)您混淆了承诺链和promise.all.chaining,当一个“有一系列异步任务要一个接一个地完成”(请参阅).Promise.all以某种方式专用于并行操作:它返回一个承诺,该承诺在数组中的所有项都满足时才会满足。请参阅。我不确定您是否要并行执行asyncFunction1和asyncFunction2。我建议您使用链接来重新计算整个过程。我希望执行asyncFunction1和asyncFunction2asyncFunction2是并行的。但是在asyncFunction2中,我想为database().ref().once()和admin.database().ref().set()链接它。将查看您共享的链接并尝试链接。非常感谢。@Doug Stevenson,看到了您的youtube视频。非常喜欢该视频。您是否有任何视频更详细地解释承诺。所有返回值?承诺是什么?所有返回值?
// Create 2 functions
function asyncFunction1(topUpObject){
    // Push top up object to database
    admin.database().ref('topupTransaction').push(topUpObject)
      .then((response) => {
        // Update databse successful (top up transaction)
        console.log('Top Up transaction created successfully!', topUpObject);
        // return res.redirect(303, response.ref);
        return topUpObject;
      }).catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return error;
      });
}

function asyncFunction2(userID,topUpObject){
    // Get the user account balance
    console.log('Current User ID: ', userID);
    var ref = admin.database().ref('users').child(userID);
    admin.database().ref('/users/' + userID).once("value",snap=> {
      // do some stuff once
      console.log('Current User Data',snap.val());
      console.log('Current User balance',snap.val().accountBalance);
      var userContents = snap.val();
      var currentBalance = userContents.accountBalance;
      var updatedBalance = currentBalance + topUpObject.amount;
      console.log('Updated Balance',updatedBalance);
      userContents.accountBalance = updatedBalance;
      /*Current User Data { 
        accountBalance: 0,
        accountCurrency: 'MYR',
        createdOn: '2018-05-02T20:42:49Z',
        phoneNumber: '+123445555555'
      }
      */
      admin.database().ref('/users/' + userID).set(userContents).then(snapshot => {
        console.log('Updated top up value! for user', topUpObject);
        return res.send(topUpObject.amount);  
      }).catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return error;
      });

    });
}

// app.post("/checkout", function (req, res) {
exports.checkout = functions.https.onRequest((req, res) => {
  var nonceFromTheClient = req.body.payment_method_nonce;
  // Use payment method nonce here

  // Create Transaction
  gateway.transaction.sale({ 
    amount: req.query.topUpPackage,
    paymentMethodNonce: nonceFromTheClient,
    options: {
      submitForSettlement: true
    }
  },(err, result) => { //TODO: What should we pass back here???
    if (err) {
    // If top up error (from braintree)
      console.log(err.stack);
    }else{
    // If top up is successful
      console.log('Result:',result);
      console.log('Top Up Package is: ', req.query.topUpPackage);
      var topUpObject = {
        amount : parseInt(req.query.topUpPackage),
        date : admin.database.ServerValue.TIMESTAMP, // 1525451616097
        user : req.query.userUid
      };
      return Promise.all([asyncFunction1(topUpObject), asyncFunction2(req.query.userUid,topUpObject)]); //TODO: how to pass back res() to client???
    }
    // Return the error as response
    return res.send(err);
  });
});

exports.client_token = functions.https.onRequest((req, res) => {

    // a token needs to be generated on each request
    // so we nest this inside the request handler

    // Need to write a function to return a client token,
    // and return it back by using the res.send command
    console.log('Log customerId',req.query.text);

    gateway.clientToken.generate({
      // customerId: req.query.text
    }, (err, response) => {
      // error handling for connection issues
      if (err) {
        console.log(err.stack);
      }else{
        clientToken = response.clientToken;
        console.log('Log Client token:',clientToken);
        return res.send(clientToken);
      }
      return res.send(err);
    });
    // return null;
});
admin.database().ref('topupTransaction').push(topUpObject)
    .then(topUpResult => {
        return admin.database().ref('/users/' + userID).once("value");
    })
    .then(oldUserData => {
         return admin.database().ref('/users/' + req.query.userUid).set(topUpObject);  
         //Set returns a non-null firebase.Promise containing void
    })
    .then(() => {  //so I don't think you can get the newUserData here
        //return res.send(newUserData.val());  <- and therefore you cannot do that here
        //But if I understand well you want to send back to the user the topUpObject, so do as follows:
        return res.status(200).send(topUpObject);  //<- note the addition of status(200) here
    })
    .catch((error) => {
        // Update databse failed (top up transaction)
        console.log('Error sending message:', error);
        return res.status(500).send(error);
});