2016-07-06 260 views
4

我知道,在的NodeJS /快速鏈的承諾最好的辦法是這樣的:最佳實踐

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

但最近不得不使用異步和Q模塊遍歷列表/數組並運行異步函數。我想知道是否有更好的方式來做/寫這個 -

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當OP沒有使用該庫時,您不能只在問題中添加[tag:Bluebird]標籤! – Bergi

+0

看看[延遲反模式](http://stackoverflow.com/q/23803743/1048572)以及如何避免它。 – Bergi

回答

2

您的代碼可以更乾淨,更短。

基本思路是

  • bluebird.js之交回調承諾,例如,promisify()可以做到這一點
  • async.each部分可重構,以Promise.all到並行調用承諾
  • 重新安排。那麼鏈
  • 的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

如果你可以請發佈重構版本。這會讓我更清楚地瞭解如何進行並加深理解。你可以跳過本質,只是重構代碼的骨架會做。謝謝。 –

+0

@SiddharthSrivastva,看到上面的例子,我已經更新了我的文章 –