Node + Q with express js - 有序的承诺

Node + Q with expressjs - ordered promisses

我想按照编写的顺序执行一组函数,最后向客户端释放请求。

例如,请参阅下面的模拟代码:

router.get('/dashboard', function(req, res, next) {

    var json = {items : 0}
    Q.fcall(
      function(){
         //first exec
         json.items+=1;
      }
    ).then(
      function(){
         //scond exec
         json.items+=1;
      }
    ).then(
      function(){
         //third exec
         json.items+=1;
      }
    ).finally(
      function(){
        //do this when all the other promises are don
        res.json(json);
     });

}

finally 函数应该在所有完成后执行。

可以用Q做吗?

更新 我想我误导了你,并没有提供所有信息,因为我认为它不相关,但它是...
我实际上是通过 mongoose 带来数据的,而 mongoose 也是异步的。
所以它是这样的:

 Q.fcall(
        function() {
            Visitor.count(dateRange, function(err, data) {
                json.newVisitors = data;
            });
        }).then(
        function() {
            Account.count(dateRange, function(err, data) {
                json.newAccounts = data;
            });
        }).finally(
        function() {
            res.json(json);
        })

是:

var path = require('path'),
    express = require('express'),
    app = express(),
    router = express.Router(),
    Q = require('q');

router.get('/dashboard', function(req, res) {

  var json = {items:''};

  Q.fcall(function() {
        json.items += 'A';
      })
      .then(function() {
        json.items += 'B';
      })
      .then(function() {
        json.items += 'C';
      })
      .finally(function() {
        res.json(json);
      });
});

app.use('/', router);

var http = require('http');

var port = process.env.PORT || '3000';
app.set('port', port);

var server = http.createServer(app);
server.listen(port);
server.on('listening', function onListening() {
      var addr = server.address();
      var bind = typeof addr === 'string'
          ? 'pipe ' + addr
          : 'port ' + addr.port;
      console.log('Listening on ' + bind);
    }
);

然后

curl localhost:3000/dashboard                                                                                                                                                                                                 

Returns:

{"items":"ABC"}

P.S. 您可能还想调查 async-q 等。其他人:

async.series([
  ->
    ### do some stuff ###
    Q 'one'
  ->
    ### do some more stuff ... ###
    Q 'two'
]).then (results) ->
    ### results is now equal to ['one', 'two'] ###
    doStuff()
  .done()

### an example using an object instead of an array ###
async.series({
  one: -> Q.delay(200).thenResolve(1)
  two: -> Q.delay(100).thenResolve(2)
}).then (results) ->
    ### results is now equal to: {one: 1, two: 2} ###
    doStuff()
  .done()

UPDATED(有点勉强,我会用async):

var path = require('path'),
    express = require('express'),
    app = express(),
    logger = require('morgan'),
    router = express.Router(),
    Q = require('q'),
    async = require('async-q');

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));

router.get('/dashboard', function(req, res) {

  var json = {};

  async.series({
        newVisitors: function() {
          return Q.Promise(function(resolve,reject) {
            console.log(arguments);
            Visitor.count(dateRange, function(err, data) {
              if(err) return reject(err);
              resolve(data);
            });
          });
        },
        newAccounts: function() {
          return Q.Promise(function(resolve,reject) {
            Account.count(dateRange, function(err, data) {
              if(err) return reject(err);
              resolve(data);
            });
          });
        }
  })
      .then(function(json) {
        res.json(json);
      });
});

app.use('/', router);

var http = require('http');

var port = process.env.PORT || '3000';
app.set('port', port);

var server = http.createServer(app);
server.listen(port);
server.on('listening', function onListening() {
      var addr = server.address();
      var bind = typeof addr === 'string'
          ? 'pipe ' + addr
          : 'port ' + addr.port;
      console.log('Listening on ' + bind);
    }
);

现在returns:

{"newVisitors": 1,"newAccounts":2}

Mongoose 已经承诺。在查询中调用 exec() 会给你一个承诺。这里有两种方法:

经典承诺链接:

Visitor.count(dateRange).exec().then(function (data) {
    json.newVisitors = data;
    return Account.count(dateRange).exec(); // return promise for chaining
}).then(function (data) {
    json.newAccounts = data;
}).then(function () {
    res.json(json);
}).catch(function (err) {
    // handle errors
});

或Promise.all:

Promise.all([
    Visitor.count(dateRange).exec(),
    Account.count(dateRange).exec()
]).then(function(result){
    // result is an ordered array of all the promises result 
    json.newVisitors = result[0];
    json.newAccounts = result[1];
}).catch(function (err) {
    // handle errors
});