我有一个中间件函数,它访问一个api并返回一个ID,这是正确的,但是在它返回数据之前调用next。视图是在第一次没有数据的情况下呈现的。我更愿意把它包装在一个承诺,并更新视图时,它是可用的。实现这一目标的最佳方式是什么。我一直在用Q服务实现一些东西,但没有任何运气。
Server.js
var app = express();
var guid = require('./server/guid.js')(app);
app.use(guid.checkGUID);guid.js
var express = require('express');
var Q = require('q');
var request = require('request');
var uuid = require('uuid');
module.exports = function(app){
var checkGUID = function(req, res, next) {
if(!app.locals.guid){
getGUID();
next();
}else{
next();
}
};
var getGUIDOptions = {
options....
};
var getGUID = function(req,res, next) {
request(getGUIDOptions, returnGUID);
};
function returnGUID(error, response, body) {
if (!error && response.statusCode == 200) {
app.locals.guid = body.guid;
return body.guid;
}else{
console.log(body);
}
};
return {
checkGUID: checkGUID
}
}发布于 2015-08-10 22:46:28
您不需要使用承诺,只需要为请求调用中间件next()回调。下面是我编写它的方式,请注意,我试图正确地处理所有预期的错误条件。
var util=require('util'),
request = require('request');
module.exports = function(app) {
/**
* Assure we have an app-wide GUID
* @param {object} req
* @param {object} res
* @param {function} next - callback to next stage in request processing
*/
var assureGUID = function(req, res, next) {
if(app.locals.guid){ // we already have one
next();
return;
}
getGUID(req, res, next);
};
/**
* Retrieve a GUID for this app
* @param {object} req
* @param {object} res
* @param {function} next - callback to next stage in request processing
*/
var getGUID = function(req, res, next) {
var getGUIDOptions = {
//options....
};
request(getGUIDOptions, function(err,resp,body){
if(err){
next(err);
return;
}
if(200 !== resp.statusCode){
next(new Error('failed to retrieve GUID, status='+resp.statusCode));
return;
}
if(!('object'===typeof body && 'string'===typeof body.guid && body.guid)){
next(new Error('failed to retrieve GUID, resp: '+util.inspect(resp,{depth:null})));
return;
}
app.locals.guid=body.guid;
next();
});
};
return {
assureGUID: assureGUID
}
};本质上,当请求击中这个处理程序,并且我们已经有了这个应用程序的GUID时,我们按下(通过调用next())。如果我们还没有GUID,就会请求一个新的GUID,当我们拥有它时,就调用next()。
如果你一意孤行,我也很乐意附上这个解决方案。
更新
好的,这是承诺(原文如此)承诺版本。我(和其他许多人)更喜欢Petka的蓝鸟承诺实现,所以我将在这里使用它而不是Q,如果需要的话,您应该能够不费吹灰之力地将这段代码转换成。
// Promises version
var util=require('util'),
Promise=require('bluebird'),
request = Promise.promisifyAll(require('request')); // see note 1.
var assureGUID = function(req,res,next){
if(app.locals.guid){ // we already have one
next();
return;
}
var getGUIDOptions = {
//options....
};
request.get(getGUIDOptions) // see note 2.
.catch(function(err){ // get request failed
next(new Error('GET request for GUID failed:'+err));
})
.spread(function(resp,body){ // see note 3.
// check for proper result
if(200 !== resp.statusCode){
throw new Error('failed to retrieve GUID, status='+resp.statusCode);
}
if(!('object'===typeof body && 'string'===typeof body.guid && body.guid)){
throw new Error('failed to retrieve GUID, resp: '+util.inspect(resp,{depth:null}));
}
app.locals.guid=body.guid;
next();
})
.catch(function(err){ // unexpected result
next(err);
});
};几个注意事项:
Promise.promisifyAll()将自动地将由request模块公开的所有函数转换为承诺,如果它们遵循标准的f(err,res)节点回调模式。request(),请参阅关于"promisification“的说明。f(err,res),则可以使用Promise.spread()“传播”基函数中的可用参数。因此,由于request.get()是通过三个arg调用的:err (由承诺消费)、res和body,因此我们需要将剩下的两个arg“扩展”到新的承诺回调中。最后,虽然我还没有测试这段代码,但它应该可以工作。如果您有任何问题,请不要犹豫,补充进一步的意见。
https://stackoverflow.com/questions/31928907
复制相似问题