Expressjs、异步和中间件无法正常工作
Expressjs, async and middleware does not work properly
我正在使用 expressjs 框架进行测试,我在其中创建了一个 运行 在路由块之前的中间件,但它无法正常工作。
我认为可能是我的代码逃避了异步并且它没有正确地运行,但我对代码做了一些更改并且错误仍然逃脱了我。对于我所做的更多测试和尝试,我找不到错误。
我的代码如下:
function getData(hostname, number, string, cb) {
async.waterfall([
function(callback) {
console.log('1');
callback(null, null);
},
function(first, callback) {
console.log('2');
callback(null, null);
},
function(second, callback) {
console.log('3');
callback(null, []);
}
],
function(err, results) {
if( typeof cb === 'function') {
return cb(null, results);
}
return results;
});
}
// Request middleware
app.use(function(req, res, next) {
res.locals['data'] = getData(req.hostname, 40, 'demo');
next();
});
app.get('/demo', function(req, res) {
res.send('Demo');
console.log( JSON.stringify( res.locals ) );
});
控制台输出如下(运行s before that middleware returns the value):
debug: 1
{}
GET /demo 200 10.654 ms - 9
debug: 2
debug: 3
GET /favicon.ico - - ms - -
只有在按以下方式修改代码后,我才能正确使用代码:
// Request middleware
app.use(function(req, res, next) {
if( req.method === 'GET' ) { // Only get request
getData(req.hostname, 40, 'demo', function(err, data) {
req.locals['data'] = data;
next();
});
} else {
next();
}
});
但我认为是扩展代码,重复调用和检查。我知道,因为它不适用于上面返回值的代码。我认为使用异步瀑布 运行 宁代码系列并且直到最后才返回它,阻塞代码。
不应该是同步和阻塞代码的延续吗?
谢谢。
正如您所指出的,问题是 getData returns 立即。 async
不是 'escape async',它是一组以异步方式 围绕控制流的模式 。结果仍然是异步的。另外,不要使用 "deasync" 库。
您可能对 koa
感兴趣,它使用生成器(需要 ES6 - 即 Node v4 或带有 --harmony 的 Node 0.12),以便让您编写更少 'callback' 驱动的代码。例如这将是 koa 中间件:
app.use(function*(next) {
res.locals['data'] = yield getData(req.hostname, 40, 'demo');
yield* next;
});
你这里有一个基本的控制流问题。您的 getData 函数试图同时是同步和异步的,同时利用纯异步控制流。
async.waterfall
方法用于执行一系列异步方法,一个接一个,将结果从一个方法传递到链中的下一个方法。如果任何方法回调出错,瀑布将被中断。
鉴于此信息,您应该重构 getData()
方法:
function getData(hostname, number, string, cb) {
async.waterfall([
function(callback) {
console.log('1');
callback();
},
function(first, callback) {
console.log('2');
callback();
},
function(second, callback) {
console.log('3');
callback(null, []);
}
],
function(err, results) {
return cb(err, results);
});
}
现在,将此方法连接到您的中间件时,您可以将 next
函数作为回调值传递:
app.use(function(req, res, next) {
getData(req.hostname, 40, 'demo', function(err, results) {
res.locals.data = results;
next(err);
});
});
我希望这是有道理的。基本上,您只是在这里混合和匹配同步和异步概念。
我正在使用 expressjs 框架进行测试,我在其中创建了一个 运行 在路由块之前的中间件,但它无法正常工作。
我认为可能是我的代码逃避了异步并且它没有正确地运行,但我对代码做了一些更改并且错误仍然逃脱了我。对于我所做的更多测试和尝试,我找不到错误。
我的代码如下:
function getData(hostname, number, string, cb) {
async.waterfall([
function(callback) {
console.log('1');
callback(null, null);
},
function(first, callback) {
console.log('2');
callback(null, null);
},
function(second, callback) {
console.log('3');
callback(null, []);
}
],
function(err, results) {
if( typeof cb === 'function') {
return cb(null, results);
}
return results;
});
}
// Request middleware
app.use(function(req, res, next) {
res.locals['data'] = getData(req.hostname, 40, 'demo');
next();
});
app.get('/demo', function(req, res) {
res.send('Demo');
console.log( JSON.stringify( res.locals ) );
});
控制台输出如下(运行s before that middleware returns the value):
debug: 1 {} GET /demo 200 10.654 ms - 9 debug: 2 debug: 3 GET /favicon.ico - - ms - -
只有在按以下方式修改代码后,我才能正确使用代码:
// Request middleware
app.use(function(req, res, next) {
if( req.method === 'GET' ) { // Only get request
getData(req.hostname, 40, 'demo', function(err, data) {
req.locals['data'] = data;
next();
});
} else {
next();
}
});
但我认为是扩展代码,重复调用和检查。我知道,因为它不适用于上面返回值的代码。我认为使用异步瀑布 运行 宁代码系列并且直到最后才返回它,阻塞代码。
不应该是同步和阻塞代码的延续吗?
谢谢。
正如您所指出的,问题是 getData returns 立即。 async
不是 'escape async',它是一组以异步方式 围绕控制流的模式 。结果仍然是异步的。另外,不要使用 "deasync" 库。
您可能对 koa
感兴趣,它使用生成器(需要 ES6 - 即 Node v4 或带有 --harmony 的 Node 0.12),以便让您编写更少 'callback' 驱动的代码。例如这将是 koa 中间件:
app.use(function*(next) {
res.locals['data'] = yield getData(req.hostname, 40, 'demo');
yield* next;
});
你这里有一个基本的控制流问题。您的 getData 函数试图同时是同步和异步的,同时利用纯异步控制流。
async.waterfall
方法用于执行一系列异步方法,一个接一个,将结果从一个方法传递到链中的下一个方法。如果任何方法回调出错,瀑布将被中断。
鉴于此信息,您应该重构 getData()
方法:
function getData(hostname, number, string, cb) {
async.waterfall([
function(callback) {
console.log('1');
callback();
},
function(first, callback) {
console.log('2');
callback();
},
function(second, callback) {
console.log('3');
callback(null, []);
}
],
function(err, results) {
return cb(err, results);
});
}
现在,将此方法连接到您的中间件时,您可以将 next
函数作为回调值传递:
app.use(function(req, res, next) {
getData(req.hostname, 40, 'demo', function(err, results) {
res.locals.data = results;
next(err);
});
});
我希望这是有道理的。基本上,您只是在这里混合和匹配同步和异步概念。