Nodejs / Express中链接promise的最佳实践

Sid*_*tva 5 javascript node.js promise express q

我知道在Nodejs / Express中兑现承诺的最佳方法是:

doSomeThing()
.then()
.then()
.catch();
Run Code Online (Sandbox Code Playgroud)

但是最近不得不使用async和q模块来遍历列表/数组并运行async函数。我想知道这样做/编写此方法的更好方法-

var deferred = Q.defer();
var deferred2 = Q.defer();          
models.Local.findOne({
        where: {
            id: parseInt(req.body.localid)
        }
    })
    .then(function(resultLocal){
        if(!resultLocal){
            return res.status(404).json(
                {
                    "status" : "error",
                    'error': "Local Not Found"
                });
        }
        return models.Documents.create(req.body.document);
    })
    .then(function(docCreated){
            var attributes = req.body.document.Attributes;
            async.each(attributes, function(item, callback) {
                models.Doc_Tags.create({
                    value: item.value,
                    attribute_id: item.id,
                    document_id: docCreated.id
                })
                .then(function(attributeCreated){
                    var upObj = {};
                    upObj[item.col_name] = item.value;

                    models[item.table_name].update(upObj,{
                        where:{
                            id: req.body.document.local_id
                        }
                    })
                    .then(function(primaryUpdated){
                        deferred2.resolve();
                    })
                    .catch(function(error){
                        return res.status(400).json({status: 'error', error:error.message});
                    });

                    deferred2.promise
                    .then(function(){
                        callback();
                    })
                    .catch(function(error){
                        return res.status(400).json({status: "error", error: error.message});
                    });

                })
                .catch(function(error){
                    return res.status(400).json({status: 'error', error:error.message});
                });
            }, function(err,r){
                if( err ) {
                    return res.status(400).json({status: 'error', error:err.message});
                } else {
                    console.log('All attributes Associated');
                    deferred.resolve(docCreated);
                }
            });
            deferred.promise.then(function(result, attributes){
                var obj = req.body.Local;
                models.Local.update(obj, {
                    where: {
                        id: result.local_id
                    }
                })
                .then(function(resultUpdate){
                    return res.status(201).json({status: "success", document: result});
                })
                .catch(function(error){
                    return res.status(400).json({status: "error", error: error.message});
                });
            })
            .catch(function(error){
                return res.status(400).json({status: "error", error: error.message});
            });
        })
    .catch(function(error){
        return res.status(400).json({status: "error", error: error.message});
    });
Run Code Online (Sandbox Code Playgroud)

如果我做错了,请纠正我。在功能方面,代码可以正常运行,但是我认为我可以以某种方式对其进行重构,以使其看起来和阅读效果更好。

谢谢。

Alo*_*mon 4

您的代码可以更干净、更短。

基本思想是

  • 将回调转为promise,例如bluebird.js的promisify()可以做到这一点
  • async.each 部分可以重构为 Promise.all 以并行调用 Promise
  • 重新排列.然后链接
  • javascript es6 比旧版本更干净

示例重构版本

const Promise = require('bluebird')

// CustomError should be separated to another node module
class CustomError {
  constructor(message, code) {
    this.code = code
    this.message = message
  }
}

let docCreated = undefined

function getPromiseParams(item) {
  return Promise.try(() => {
    return models.Doc_Tags.create({
        value: item.value,
        attribute_id: item.id,
        document_id: docCreated.id
    })
  }).then(attributeCreated => {
    const upObj = {};
    upObj[item.col_name] = item.value;
    return models[item.table_name].update(upObj, { where:{ id: req.body.document.local_id } })
  }).then(primaryUpdated => {
    return docCreated
  }).catch(error => {
    throw new CustomError(error.message, 400)
  })
}

Promise.try(() => {
  return models.Local.findOne({ where: { id: parseInt(req.body.localid) } })
  }).then(resultLocal => {
    if(!resultLocal) throw new CustomError('Local Not Found', 404)

    return models.Documents.create(req.body.document)
  }).then(_docCreated => {
    docCreated = _docCreated // assign value to docCreated

    const attributes = req.body.document.Attributes
    const promiseParams = attributes.map(item => getPromiseParams(item))
    return Promise.all(promiseParams)
  }).then(() => {
    const obj = req.body.Local
    return models.Local.update(obj, { where: { id: result.local_id }})
  }).then(() => {
    return res.status(201).json({status: "success", document: docCreated})
  }).catch(error => {
    return res.status(error.code || 400).json({status: "error", error: error.message});
  })
Run Code Online (Sandbox Code Playgroud)