然后执行有条件的

时间:2019-03-17 06:58:41

标签: javascript promise es6-promise

如何有条件地不履行诺言而无所作为。我创建了一个嵌套的承诺,到那时我有7个。但是有条件地,我需要跳过几个.then而在那个块中什么也不做,如何实现呢?

我的完整代码

const admin = require('firebase-admin');
const rp = require('request-promise');

module.exports = function(req, res) {

const phone = String(req.body.phone).replace(/[^\d]/g, '');
const amount = parseInt(req.body.amount);
const couponCodeName = (req.body.couponCodeName);
const couponUsage = parseInt(req.body.couponUsage);
const usersCouponUsage = parseInt(req.body.usersCouponUsage);
const finalAddress = (req.body.finalAddress);
const planName = (req.body.planName);
const saveThisAddress = (req.body.saveThisAddress);
const orderNumber = (req.body.orderNumber);
const pay_id = (req.body.pay_id);

const options = {
    method: 'POST',
    uri:`https://..........`,
    body: {
        amount
    },
    json: true
};

return admin.auth().getUser(phone)
.then(userRecord => {

    return rp(options)
})
.then((orderResponse) => {
    return admin.database().ref('trs/'+ phone)
        .push({ pay_id: orderResponse.id })
    })
.then(() => {
    return admin.database().ref('ors/'+ phone)
        .push({ pay_id })
})
.then(() => { 
    return saveThisAddress === true ? 
        admin.database().ref('address/'+phone)
            .push({address: finalAddress}) : null
})
.then(() => {
    return admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
        .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false}, () => {
            res.status(200).send({ success:true })
        })
}) 
.then(() => {
    return couponCodeName === "" ? null : 
        admin.database().ref(`couponCodes/${couponCodeName}`)
            .update({couponUsage: couponUsage + 1 })
})
.then(() => {
    return usersCouponUsage === "" ? null : 
        admin.database().ref(`couponUsage/${phone}`)
            .update({ [couponCodeName]: usersCouponUsage + 1 })
})
.catch((err) => {
    res.status(422).send({ error: err })
})    
 .catch((err) => {
 res.status(422).send({error: err });
 });
 }

从上面的代码开始,最后两个.then有条件返回couponCodeName ===“”? null:代码...)}。

我需要实现的是,当couponCodeName ===“”时,它应该跳过.then块而什么也不做。但是,我在此返回null,它引发了未处理的拒绝错误。那么如何实现呢?如何跳过.then,然后什么也不做(不执行任何操作,简单地跳过它很重要)怎么做?

我得到的错误是:我从这些嵌套中得到的错误。然后是“未处理的拒绝”和“错误:发送标头后无法设置标头。”

来自Google Cloud Function的错误

Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:369:11)
at ServerResponse.header (/var/tmp/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/var/tmp/worker/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/var/tmp/worker/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/var/tmp/worker/node_modules/express/lib/response.js:158:21)
at admin.auth.getUser.then.then.then.then.then.then.then.catch.catch (/user_code/request_payment_details.js:86:28)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

还有

Unhandled rejection

注意:Node Js版本:6(所以我正式认为,我不能使用async和await)

4 个答案:

答案 0 :(得分:3)

也许您可以使用this,因为您需要同步:

menuBar

答案 1 :(得分:1)

第1部分:您的错误处理程序不应崩溃。

如果您调用res.status(200),则Express开始将数据流传输到客户端(标头已经发送)。之后,您无法使用res.status(500)更改响应状态,因为状态代码已经在发送到客户端了。

 stuff()
 .then(result => {
   res.status(200).send(result); // server starts sending
 }).then(moreStuff) // error occurs here
 .catch(error => {
   res.status(500).send(error); // fails, as server is already sending
 });

要解决此问题,您应该仅在完成所有任务后才开始流式传输任何数据:

 stuff().then(moreStuff).then(evenMoreStuff) // error occurs here
   .then(result => {
      res.status(200).send(result); // doesnt get executed
   }).catch(error => {
      console.error(error);
      res.status(500).send("Whoops, server error\n" + error.message); // works
   });

第2部分:根本不应该出错。

现在,错误处理程序可以正常工作,您应该能够找出代码中实际出了什么问题。

(如果没有正确的错误消息,我们将无法为您提供帮助


第3部分:实现所需的条件执行:

要有条件地执行承诺,您必须将它们嵌套:

 a().then(() => {
  if(!stuff) return; // exit early, continue at next then

  return b().then(c); // conditionally execute b and c
 }).then(rest); // executes after b and c if stuff is true

第4部分:现在一切正常,您可以将代码重构为async / await,使其更具可读性:

正如您指出的那样,v6 dpes不支持async / await,您必须migrate to v8transpile it down with webpack

module.exports = async function(req, res) {
  try {
     //...
     const userRecord = await admin.auth().getUser(phone);
     const orderResponse = await rp(options)

     await admin.database().ref('trs/'+ phone)
      .push({ pay_id: orderResponse.id });

     await admin.database().ref('ors/'+ phone)
      .push({ pay_id })

     if(saveThisAddress === true) {
       await admin.database().ref('address/'+phone)
        .push({address: finalAddress});
     }

     await admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
      .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false});

     if(couponCodeName !== "") {       
       await admin.database().ref(`couponCodes/${couponCodeName}`)
        .update({couponUsage: couponUsage + 1 });
     }

     if(usersCouponUsage !== "") {
       await admin.database().ref(`couponUsage/${phone}`)
        .update({ [couponCodeName]: usersCouponUsage + 1 });
     }

     res.status(200).send({ success:true });
  } catch(error) {
    console.error("Error inside API", error);
    res.status(422).send({ error });
  }
};

答案 2 :(得分:0)

怎么样

.then(() => {
            return couponCodeName === "" ? null : 
                admin.database().ref(`couponCodes/${couponCodeName}`)
                    .update({couponUsage: couponUsage + 1 })
                .then(() => {
                            admin.database().ref(`couponUsage/${phone}`)
                                .update({ [couponCodeName]: usersCouponUsage + 1 })
                            })}

答案 3 :(得分:0)

请说是否要忽略此阻止:

.then(() => {
    return admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
        .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false}, () => {
            res.status(200).send({ success:true })
        })
}) 

您只需返回一个已解决的承诺,然后再转到下一个,就像这样:

.then(() => {
    if (<some-conditions>) {
       return Promise.resolve(<optional-data>);   
    } else {    // If directly want to go to first catch statement following
       return Promise.reject(<optional-data>)
    }

    return admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
        .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false}, () => {
            res.status(200).send({ success:true })
        })
}) 

如果您忽略此代码块:

.then(() => {
    return couponCodeName === "" ? null : 
        admin.database().ref(`couponCodes/${couponCodeName}`)
            .update({couponUsage: couponUsage + 1 })
})

像这样放置它:

.then(() => {
    return couponCodeName ? Promise.resolve() :      // "" and null evaluates to false
        admin.database().ref(`couponCodes/${couponCodeName}`)
            .update({couponUsage: couponUsage + 1 })
})

enter image description here

快乐编码