如何在 bluebird 承诺中修改 express.res,并在另一个承诺中使用 res?

How can you modify express.res within bluebird promises, and use res within another promise?

我可能想多了,但请耐心等待...如果我有以下代码

app.get('/api/endpoint', function(req, res, next) {
    new Promise(function() {
        // doing something that takes lots of code
        return someJson
    })
    .then(function(someJson) {
        // analyze someJson with lots of code
    })
    .then(function() {
        // do more
    })
    // chain a bunch more promises here
    .then(function() {
        res.status(200).send(message)
    })
    .catch(function(err) {
        // error handling
    })
    .finally(function() {
        // clean up
    })
})

如果承诺链变得很长,导航端点可能会很痛苦。所以,我希望承诺的每一步都是它自己的功能(以简化上面的代码)。所以我可以这样重写前 2 个承诺:

function findSomeJson() {
    return new Promise(function() {
        // doing something that takes lots of code
        return someJson
    })
}

function analyzeSomeJson(someJson) {
    return new Promise(function(someJson) {
        // analyze someJson with lots of code
    })
}

现在,这些函数中的每一个都可以像这样在原始示例中使用:

findSomeJson()
.then(function(someJson) {
    return analyzeSomeJson(someJson)
})
// etc...

但是,如果我需要在这些承诺范围内调整 res 会怎样?我是否需要每次 return res 并将 someJson 存储在 res 中?而且,如果我必须使用 next() 会怎样?如何确保 res 在我的承诺链末尾被修改?我不能在 finally() 中做到这一点,我是否必须在我最后的承诺中做到这一点?

如果您真的希望能够从您的函数中改变 res,您必须传递它。我认为传递它的 easiest/cleanest 方法是像这样使用 bind

findSomeJson()
  .then(analyzeSomeJson.bind(this, res))
  .then(doMore.bind(this, res))
  .then(andEvenMore.bind(this, res))...

那么 analyzeSomeJson 定义将如下所示:

// .bind makes it so that res is the first argument when it is called
function analyzeSomeJson(res, someJson) {
  return new Promise(function(someJson) {
    // analyze someJson with lots of code
  })
}

但我可能会尽量避免绕过 res,这样只有您的控制器必须知道 reqres。您可以将所有功能移动到一个或多个服务,并让控制器根据服务 return 确定 res 需要发生什么。希望这会导致 maintainable/testable 代码。

更新 非常简单的服务示例

// endpoint.js
var jsonService = require('./jsonService.js');

app.get('/api/endpoint', function(req, res, next) {
  jsonService.getJson()
  // chain a bunch more promises here
  .then(function(json) {
    if(json === null) {
      return res.status(404).send('Not Found');
    }
    res.status(200).send(json);
  })
  .catch(function(err) {
      // error handling
  });
});

您可以通过多种方式实现您的服务,但实际上它只是您在 "controller" 或 endpoint.js 中需要的另一个 .js 文件。无论您导出什么,都将是您的 "public" 方法。

// jsonService.js

// "public" methods
var service = {
  getJson: function() {
    return findSomeJson().then(analyzeSomeJson);
  }
};

module.exports = service;

// "private" methods
function findSomeJson() {
  return new Promise(function() {
      // doing something that takes lots of code
      return someJson
  });
}

function analyzeSomeJson(someJson) {
  return new Promise(function(someJson) {
      // analyze someJson with lots of code
  });
}