2016-07-06 6 views
4

Я знаю, что лучший способ цепи обещаний в Nodejs/Экспрессе как:Лучшая практика для построения цепочки обещаний Nodejs/Экспресс

doSomeThing() 
.then() 
.then() 
.catch(); 

Но недавно пришлось использовать асинхронный и Q модуль перебрать список/array и запустить функцию 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}); 
    }); 

Пожалуйста, поправьте меня, если я делаю что-то неправильно. Функциональность мудрый код работает правильно, но я думаю, что я могу реорганизовать его как-то выглядеть и читать лучше.

Спасибо.

+0

Не использовать 'async.js' вместе с обещаниями - это самая важная хорошая практика здесь. – Bergi

+0

@AlongkornChetasumon Вы не можете просто добавить тег [tag: Bluebird] к вопросу, когда OP не использует эту библиотеку! – Bergi

+0

Посмотрите на [отложенный антипаттерн] (http://stackoverflow.com/q/23803743/1048572) и как его избежать. – Bergi

ответ

2

Ваш код может быть чище и короче.

основные идеи

  • очередь обратного вызова пообещать, например, promisify() из bluebird.js может сделать
  • async.each часть может быть рефакторинг к Promise.all назвать Promise
  • параллельно
  • повторно организовать .then цепи
  • 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}); 
    }) 
+0

Если вы могли бы отправить обновленную версию. Это даст мне больше ясности о том, как действовать дальше и понимать. Вы можете пропустить nitty gritty, и только скелет реорганизованного кода будет делать. Благодарю. –

+0

@SiddharthSrivastva, см. Пример выше, я обновил сообщение –