簡體   English   中英

node.js鏈多個promises(用mongoose)

[英]node.js chain multiple promises (with mongoose)

以下是我正在處理的典型承諾函數。

var _delete = function(t, id) { 
  return Promise.cast(Event.find({where: {id: id}}, {transaction: t}))
  .then(function(d){
    if (d) {
      // ------- (*)
      return Promise.cast(d.updateAttributes({status: -1}, {transaction: t}))
      .then(function(){
          // do inventory stuff 
          return Promise.cast(Inventory.update({}).exec())
          .then(function(d){
               // do something 
          })
      }).then(function(){
          // do product stuff
          return Promise.cast(Product.update({}).exec())
          .then(function(d){
               // do something 
          })
      })
    } else {
      return Promise.reject('this transaction list does not exist');
    }
  });
};

這看起來不錯,直到我處理更復雜的更新/創建代碼將變得非常混亂。

目前我正在承諾的是1.我有很多無用的返回真實語句,唯一的目的是轉到下一個。然后聲明2. promise以嵌套方式編程。 輸入參數通常很復雜,並且有超過1個參數,所以我不能做這樣的事情

.then(fun1).then(fun2)

......等

這使我無法'tap' .then語句來啟用/禁用功能。

所以我的問題是如何正確地做到這一點? 謝謝..


以下是我所說的非常丑陋的事情....

var _process = function(t, tid) {
  var that = this;
  return Promise.cast(Usermain.find({where: {transaction_id: tid}}))
  .bind({})  // --- (*)
  .then(function(d){
    this.tmain = d;
    return true;   // ---- do nothing, just go to next thennable (is this correct)
  }).then(function(){
    return Promise.cast(Userlist.findAndCountAll({where: {transaction_id: tid}}))
  }).then(function(d){
    this.tlist = d;
    return true;  // ---- do nothing, just go to next thennable (is this correct)
  }).then(function(){
    if (this.tmain.is_processed) {
      return Promise.reject('something is wrong');
    }
    if (this.tlist.count !== this.tmain.num_of_tran) {
      return Promise.reject('wrong');
    }
    return Promise.resolve(JSON.parse(JSON.stringify(this.tlist.rows)))
    .map(function(d){
      if (d.is_processed) return Promise.reject('something is wrong with tran list');
      return true;  // goto next then
    });
  }).then(function(){
    return Promise.cast(this.tmain.updateAttributes({is_processed: 1}, {transaction: t}));
  }).then(function(){
    return Promise.resolve(this.tlist.rows)
    .map(function(d){
      var tranlist = JSON.parse(JSON.stringify(d));
      return Promise.cast(d.updateAttributes({is_processed: 1, date_processed: Date.now()}, {transaction: t}))
      .then(function(d){
        if (!d) {
          return Promise.reject('cannot update tran main somehow');
        } else {
            if (tranlist.amount < 0) {
              return Usermoney._payBalance(t, tranlist.user_id, -tranlist.amount);
            } else {
              return Usermoney._receiveBalance(t, tranlist.user_id, tranlist.amount);
            }
          }
      });
    });
  });
}

你可以做兩件事:

  • Unnest then回調
  • 模塊化。 這些“做產品的東西”和“做庫存的東西”的東西可能會成為他們自己的功能(甚至是相同的?)。

在這種情況下,可以執行以下操作(假設您的注釋部分中不需要關閉):

function _delete(t, id) { 
    return Promise.cast(Event.find({where: {id: id}}, {transaction: t}))
    .then(function(d){
        if (d) {
            return Promise.cast(d.updateAttributes({status: -1}, {transaction: t}));
        else
            throw new Error('this transaction list does not exist');
    })
    .then(function(){
        // do inventory stuff 
        return Promise.cast(Inventory.update({}).exec())
    })
    .then(function(d){
        // do something 
    })
    .then(function(){
        // do product stuff
        return Promise.cast(Product.update({}).exec())
    })
    .then(function(d){
        // do something 
    });
}

在我的項目中,我使用Async.js

我認為你需要將_process方法分解為_process

  1. 依賴於先前操作的結果的操作 - 異步waterfall模式可能在此處使用
  2. 不依賴於先前動作的動作結果,它們可以並行執行
  3. 使用一些自定義過程

以下是我的應用中的示例:

async.waterfall([

    function findUser(next) {
        Users.findById(userId, function (err, user){
            if(err) {
                next(new Error(util.format('User [%s] was not found.', userId)));
                return;
            }

            next(null, user);
        });
    },

    function findUserStoriesAndSurveys(user, next) {

        async.parallel([
            function findStories(callback) {
                // find all user stories

                Stories.find({ UserGroups: { $in : user.Groups } })
                    .populate('Topic')
                    .populate('Episodes')
                    .exec(function(err, stories) {
                        if(err) {
                            callback(err);
                            return;
                        }

                        callback(null, stories);
                    });
            },
            function findSurveys(callback) {
                // find all completed surveys

                Surveys.find({
                    User: user
                }).exec(function(err, surveys) {
                    if(err) {
                        callback(err);
                        return;
                    }

                    callback(null, surveys);
                });
            }
        ],
        function(err, results) {
            if(err) {
                next(err);
                return;
            }

            next(null, results[0], results[1]);
        });
    },

    function calculateResult(stories, surveys, next) {

        // do sth with stories and surveys

        next(null, { /* result object */ });
    }

], function (err, resultObject) {
    if (err) {
        res.render('error_template', {
            status: 500,
            message: 'Oops! Server error! Please reload the page.'
        });
    }

    res.send(/* .... */);
});

請參閱Async文檔以獲取自定義過程,它確實包含許多常見模式,我也在我的客戶端JavaScript中使用此庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM