重构承诺javascript代码

时间:2017-10-31 11:46:20

标签: javascript node.js mongoose

基本上,我有一个代码来批准订单代码,方法是将用户输入的优惠券应用到订单交易中:

var Order = require('../models/order');
var Product = require('../models/product');
var Coupon = require('../models/coupon');

var _ = require('lodash');

exports.approveOrder = function(req, res) {
    var tempProducts;    
    var tempCoupon;
    var orderNbr = req.params.OrderNbr;
    if (orderNbr != undefined && orderNbr != '')
    {
        Order.findOne({ OrderNbr: orderNbr }).exec()
        .then(function(order) {
            if (order == undefined) {
                throw "Order " + orderNbr + " does not exist.";
            }
            else {
                if (order.OrderLines.length <= 0) throw "Ensure your Order has at least one order line.";

                if (req.body.CouponCode != undefined && req.body.CouponCode != '') {
                    // ***********************************************
                    // Want to refactor this following codes into some functions
                    // ***********************************************                  
                    Coupon.findOne({ CouponCode: req.body.CouponCode }).exec()
                    .then(function(coupon) {                        
                        if (coupon == undefined) {
                            throw "Coupon " + req.body.CouponCode + " does not exist.";
                        }
                        else {
                            if (coupon.Qty > 0 && (coupon.ValidFrom <= new Date() && coupon.ValidTo >= new Date())) {
                                coupon.Qty -= 1;
                                tempCoupon = coupon;

                                var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
                                return Product.find({ ProdNbr: { $in : prodNbrs } }).exec();
                            }
                            else {
                                throw "Coupon " + coupon.CouponCode + " is not valid.";
                            }
                        }
                    })
                    .then(function(products) {
                        var prodNbrs = _.map(order.OrderLines, 'ProdNbr');                                                
                        var totalQtyPerProd = 0;

                        _.forEach(products, function(product) {
                            totalQtyPerProd = _.sumBy(order.OrderLines, function(line) {
                                if (product.ProdNbr == line.ProdNbr) return line.Qty;
                            })
                            if (product.QtyOnHand - totalQtyPerProd < 0) throw "Product " + product.ProdNbr + " has insufficient quantity on hand.";

                            _.remove(prodNbrs, function(nbr) { return nbr == product.ProdNbr });
                            product.QtyOnHand -= totalQtyPerProd;

                            var totalDiscount = tempCoupon.Value / order.OrderLines.length;
                            if (tempCoupon.IsPercentage) {
                                totalDiscount = 1 - (tempCoupon.Value / 100);
                            }

                            _.forEach(order.OrderLines, function(line) {
                                if (line.ProdNbr == product.ProdNbr) {
                                    line.UnitPrice = product.UnitPrice;

                                    line.Amount = (line.Qty * line.UnitPrice) - totalDiscount;
                                    if (line.Amount < 0) line.Amount = 0;
                                    if (tempCoupon.IsPercentage) {
                                        line.Amount = (line.Qty * line.UnitPrice) * totalDiscount;
                                    }
                                }
                            })
                        })

                        if (prodNbrs.length > 0) throw "Product " + prodNbrs[0] + " does not exist.";

                        tempProducts = products;

                        order.CouponCode = tempCoupon.CouponCode;
                        order.Status = 'S';
                        return order.save();
                    })
                    .then(function() {
                        return tempCoupon.save();
                    })
                    .then(function() {
                        _.forEach(tempProducts, function(product) {
                            product.save()
                            .then(function() {

                            })
                            .catch(function(err) {
                                if (err) res.status('500').jsonp({ error: err });
                            });
                        })
                        res.status('200').jsonp({ information: "Order "+ order.OrderNbr +" has been submitted successfully." });
                    })
                    .catch(function(err) {
                        if (err) res.status('500').jsonp({ error: err });
                    });
                }
            }            
        }) 
        .catch(function(err) {
            if (err) res.status('500').jsonp({ error: err });
        });
    }
    else {
        res.status('500').jsonp({ error: "Order Number must be specified." });
    }
};

我想分别编码代码&#39;然后&#39;子句进入一些功能:

  1. 找到优惠券然后退回优惠券。
  2. 更新订单行金额
  3. 更新优惠券
  4. 返回确认消息
  5. 我尝试使用局部变量来保留找到的优惠券,不幸的是,如果变量是在findOne()方法之外的话,那么变量将是未定义的,所以在这段代码中我使用了很多很长的&#39;然后#39;在findOne()

    有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我建议您使用瀑布方法来使用async库。从本质上讲,通过使用回调,它将允许您在没有嵌套的情况下拥有更平坦的结构。

这样的事情:

var async = require('async');

var findCoupons = function(cb) {
    //do something
    cb(null, 'success');
}

var updateOrders = function(data, cb) {
    //do something
    console.log(data); //success
    cb(null, 'etc.');
}

...

async.waterfall([
    findCoupons,
    updateOrders,
    updateCoupon,
    confirmMessage
], function(err, result) {
    //all functions have finished running, do something.
});

答案 1 :(得分:1)

您使用&#34;然后链#34;很好。 我将重构代码,创建在链中使用的分离函数,如下所示:

var saveProducts = function() {
                        _.forEach(tempProducts, function(product) {
                            product.save()
                            .then(function() {

                            })
                            .catch(function(err) {
                                if (err) res.status('500').jsonp({ error: err });
                            });
                        })
                        res.status('200').jsonp({ information: "Order "+ order.OrderNbr +" has been submitted successfully." });
                    }

var saveCoupon = function() {
                        return tempCoupon.save();
                    }

var products = function(products) {
                        var prodNbrs = _.map(order.OrderLines, 'ProdNbr');                                                
                        var totalQtyPerProd = 0;

                        _.forEach(products, function(product) {
                            totalQtyPerProd = _.sumBy(order.OrderLines, function(line) {
                                if (product.ProdNbr == line.ProdNbr) return line.Qty;
                            })
                            if (product.QtyOnHand - totalQtyPerProd < 0) throw "Product " + product.ProdNbr + " has insufficient quantity on hand.";

                            _.remove(prodNbrs, function(nbr) { return nbr == product.ProdNbr });
                            product.QtyOnHand -= totalQtyPerProd;

                            var totalDiscount = tempCoupon.Value / order.OrderLines.length;
                            if (tempCoupon.IsPercentage) {
                                totalDiscount = 1 - (tempCoupon.Value / 100);
                            }

                            _.forEach(order.OrderLines, function(line) {
                                if (line.ProdNbr == product.ProdNbr) {
                                    line.UnitPrice = product.UnitPrice;

                                    line.Amount = (line.Qty * line.UnitPrice) - totalDiscount;
                                    if (line.Amount < 0) line.Amount = 0;
                                    if (tempCoupon.IsPercentage) {
                                        line.Amount = (line.Qty * line.UnitPrice) * totalDiscount;
                                    }
                                }
                            })
                        })

                        if (prodNbrs.length > 0) throw "Product " + prodNbrs[0] + " does not exist.";

                        tempProducts = products;

                        order.CouponCode = tempCoupon.CouponCode;
                        order.Status = 'S';
                        return order.save();
                    }

var getProducts = function(coupon) {                        
                        if (coupon == undefined) {
                            throw "Coupon " + req.body.CouponCode + " does not exist.";
                        }
                        else {
                            if (coupon.Qty > 0 && (coupon.ValidFrom <= new Date() && coupon.ValidTo >= new Date())) {
                                coupon.Qty -= 1;
                                tempCoupon = coupon;

                                var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
                                return Product.find({ ProdNbr: { $in : prodNbrs } }).exec();
                            }
                            else {
                                throw "Coupon " + coupon.CouponCode + " is not valid.";
                            }
                        }
                    }

exports.approveOrder = function(req, res) {
    var tempProducts;    
    var tempCoupon;
    var orderNbr = req.params.OrderNbr;
    if (orderNbr != undefined && orderNbr != '')
    {
        Order.findOne({ OrderNbr: orderNbr }).exec()
        .then(function(order) {
            if (order == undefined) {
                throw "Order " + orderNbr + " does not exist.";
            }
            else {
                if (order.OrderLines.length <= 0) throw "Ensure your Order has at least one order line.";

                if (req.body.CouponCode != undefined && req.body.CouponCode != '') {
                    // ***********************************************
                    // Want to refactor this following codes into some functions
                    // ***********************************************                  
                    Coupon.findOne({ CouponCode: req.body.CouponCode }).exec()
                    .then(getProducts)
                    .then(products)
                    .then(saveCoupon)
                    .then(saveProducts)
                    .catch(function(err) {
                        if (err) res.status('500').jsonp({ error: err });
                    });
                }
            }            
        }) 
        .catch(function(err) {
            if (err) res.status('500').jsonp({ error: err });
        });
    }
    else {
        res.status('500').jsonp({ error: "Order Number must be specified." });
    }
};

每个函数的结果将传递给链中的下一个

我建议使用最佳做法承诺

https://github.com/airbnb/javascript/issues/216