Taking into account this example:

app.get('/url/:param', function(req, res, next) {
  var param = req.params.param;
  method1(param, function(err, model) {
    if(err) return next(err);
    method2(model, function(err, models) {
      if(err) return next(err);
      if(models.length > 0) {
        method3(mode, models, function(err, models2) {
          res.render("index.html", {model: model, models: models, models2: models2});
        });
      } else {
        res.render("index.html", {model: model, models: models});
      }
    });
  });
}

Is there a way to simplify this example using promises? Look that all methods are dependants and have validations like if(models.length > 0) Furthermore I need to group the res.render in a unique place.

有帮助吗?

解决方案

Assuming Bluebird, utilizing the library features and removing the nesting:

var api = Promise.promisifyAll({method1:method1,method2:method2:method3:method3});
api.method1Async(req.params.param).then(function(res){
     return [method2Async(res),{model:res}];
}).spread(function(res,result){
     result.models = res;
     if(models.length > 0){
         return method3Async(mode,res).then(function(res){
             result.models2 = res;
         }).return(result);
     }
     return results;
}).then(function(results){
     res.render("index.html",results);
}).catch(next); // also handle render errors

Alternatively, you can do something like which has even less nesting:

var api = Promise.promisifyAll({method1:method1,method2:method2:method3:method3});
var p1 = api.method1Async(req.params.param);
var p2 = p1.then(api.method2Async);
var p3 = p2.then(function(models){ 
    if(models.length > 0) return api.method3Async(mode,models);
});
Promise.all([p1,p2,p3]).spread(function(r1,r2,r3){
    var results = {model:r1,models:r2};
    if(models.length > 0) results.models2 = r3;
    res.render("index.html",results);
}).catch(next)

Or, you can use Bluebird coroutines (needs --harmony-generators flag)

var api = Promise.promisifyAll({method1:method1,method2:method2:method3:method3});
Promise.coroutine(function*(){
    var model = yield method1Async(req.params.param);
    var models = yield method2Async(model);
    if(models.length > 0){
        var models2 = yield method3Async(mode,models);     
    }
    res.render("index.html",{model:model,models:models,models2:models2});
})().catch(next); // should probably extract to a clear method rather than self invoke

其他提示

Yes, there is. You can reduce this to one promise that fails or succeeds, and install next and res.render as the respective handlers. However, since the results are dependent on all the previous ones, the pyramid stays the easiest. Assuming Q.js:

app.get('/url/:param', function(req, res, next) {
  Q.nfcall(method1, req.params.param).then(function(model) {
    return Q.nfcall(method2, model).then(function(models) {
      if(models.length > 0)
        return Q.nfcall(method3, mode, models).catch(function(err) {
          // you're not dealing with errors here
          // omit this `.catch()` call if you want to let it reach the `next()`
        }).then(function(models2) {
          return {model: model, models: models, models2: models2};
        });
      else
        return {model: model, models: models};
      }
    });
  }).done(function(results) {
    res.render("index.html", results);
  }, next);
}

If I got you right and If you need to make a lot of nested statements, maybe you could check this out. Async can help you out calling various functions on the row (there are a lot of ways to accomplish it using Async, see its documentation further) and you can aling all statements together.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top