我在Node.js中使用express,并且在get route中使用了一个函数... 该函数首先实现了自己编码的简单缓存功能,然后从MSSQL数据库查询一些数据,并将其返回到res.json(data)中。但是我想重构我的兑现功能,并将其放在自己的函数中,并称为快速中间件。但是不知何故,我尝试了很多,但真的不知道该怎么做。下面是我的重构函数checkTime()。
router.get("/v1/watch/readindex", async function(req,res) {
///////////////////////////CASHING///////////////////////////////////
var timediff = config.get('write.cachetime'); //get cachetime - same for write or read
timediff = 30000; //testing
var timenow = Date.now();
if (!cachedtimeread || !readmsg || (cachedtimeread < (timenow-timediff))) {
readmsg = "";
cachedtimeread = timenow;
readtimemsg = `Zeit vergangen seit letztem Aufruf: ${msToTime(cachedtimeread -timenow)}. API wurde aufgerufen.\n<br>`;
}
else if (cachedtimeread >= (timenow - timediff)) { //API-Aufruf jünger als Aufrufzeitpunkt - timediff
readmsg += `Zeit vergangen seit letztem Aufruf: ${msToTime(cachedtimeread -timenow)}. Dokument ist aus dem Cache!\n<br>`;
//console.log("Funktion für Dokument-Query wurde nicht aufgerufen!");
res.set('Content-Type', 'text/html');
res.json(readmsg);
return;
}
//////////////////////////////////////////////////////////////////////
axios.all([read = await count_ES_read(), await mssqlQuery(mssqlQueryLessOneDay),
await mssqlQuery(mssqlQueryLessEightHours), await mssqlQuery(mssqlQueryTotal) ])
.then(axios.spread(function (resultES_read, mssqlLessOneDay, mssqlLessEightHours, mssqlTotal) {
readmsg='';
var elasticsearchcount = resultES_read.count;
var mssqlLessOneDay = mssqlLessOneDay.recordset[0].count;
var mssqlLessEightHours = mssqlLessEightHours.recordset[0].count;
var mssqlTotal = mssqlTotal.recordset[0].count;
//console.log(elasticsearchcount, mssqlLessOneDay, mssqlLessEightHours, mssqlTotal);
readmsg += `Umgebung: ${process.env.NODE_ENV} READ<br>`;
readmsg += `ES Dokumente insg: ${elasticsearchcount} MSSQL Dokumente insg: ${mssqlTotal} <br>`;
if ( elasticsearchcount < mssqlLessOneDay) {
readmsg += `Critical: ${mssqlLessOneDay - elasticsearchcount} , weniger Dokumente in ES als im Dokumente-Pool die älter als 1 Tag sind. <br>`;
} if ((elasticsearchcount < mssqlLessEightHours)) {
readmsg += `Warning: ${mssqlLessEightHours - elasticsearchcount} , weniger Dokumente in ES als im Dokumente-Pool, die älter als 8 Stunden sind. <br>`;
} if ((elasticsearchcount > mssqlTotal)) {
readmsg += `Achtung: ES-Dokumente Anzahl > Dokumente im Dokumente-Pool. Es gibt ${elasticsearchcount - mssqlTotal} ungelöschte Dokumente im Elasticsearch Index!`;
}
res.set('Content-Type', 'text/html');
res.json(readmsg);
})).catch((err) => {
res.send(err);
});
});
如果最后一个api-route调用的时间戳仍小于某个毫秒(以毫秒为单位)的时间戳,则此函数应从上述最后一个async-function的数据库查询中检索消息的输出。如果不是这种情况,则应执行最后一个检索数据的函数。
但是我不知道如何从异步函数中检索消息变量,以某种方式将其保存在res.locals
中,此外,我也不知道该如何跳过最后一个函数调用。不知何故,中间件中的res.json()之后的返回不起作用,并且总是执行async-function,但是如果文档比年轻,我想退出checkTime()函数并在res.json中返回消息now-timestamp
。
function checkTime(writemsg) {
return function(req,res,next) {
var timediff = config.get('write.cachetime'); //get cachetime - same for write or read
timediff = 30000; //testing
var timenow = Date.now();
if (!cachedtimewrite || !writemsg || (cachedtimewrite < (timenow-timediff))) {
writemsg = "";
cachedtimewrite = timenow;
writetimemsg = `Zeit vergangen seit letztem Aufruf: ${msToTime(cachedtimewrite -timenow)}. API wurde aufgerufen.\n<br>`;
next();
}
else if (cachedtimewrite >= (timenow - timediff)) { //API-Aufruf jünger als Aufrufzeitpunkt - timediff
writemsg += `Zeit vergangen seit letztem Aufruf: ${msToTime(cachedtimewrite -timenow)}. Dokument ist aus dem Cache!\n<br>`;
//console.log("Funktion für Dokument-Query wurde nicht aufgerufen!");
res.set('Content-Type', 'text/html');
res.json( writemsg);
return;
}
}
}
router.get("/v1/watch/writeindex", checkTime(writemsg), async function(req,res,next) {
//////////////编辑:
我在Promise.all()中用于从db获取数据的功能之一是:
var mssqlQuery = (query) => {
if (!query || query =="") {
throw new Error('Query for MSSQL was not defined!');
}
//console.log("Query: ", query);
var conn = new sql.ConnectionPool(mssqlconfig);
var req = new sql.Request(conn);
return conn.connect().then(async() => {
var result = await req.query(query);
//conn.close();
return result;
//conn.close();
}).catch(e => {
return e;
}).finally(() => {
conn.close();
});
}
答案 0 :(得分:0)
或者我在理解您的问题时遇到问题,或者您不太了解快速中间件的工作原理。
function checkTime(writemsg) {
return function(req,res,next) {
if(foo) {
req.storeValueKey = 'data to store'
next(); // run next middleware
} else {
res.json('stop processing');
}
}
}
router.get('/url',checkTime('message'), (req, res) => {
console.log('data form middleware', req.storeValueKey)
res.json('send data collected from DB' + req.storeValueKey);
req.session.storeValueForNextRequests = 'val';
})
//开始编辑
在中间件中,您可以使用next()
或res.send()
。同时使用两者是错误的。并且必须记住,使用next()
和res.send()
不会中断父函数的执行。 (记住return
)
res.send('Text response');
next();
thisIsAlsoRun();
您知道,在中间件中是“黑洞”。如果两个if
都false
都停留在中间件中,那么请添加else next()
以避免这种情况
//编辑结束
此外,我还被一个问题困扰:为什么您使用HTTP客户端从promise收集数据,为什么在那使用await?
Node应该一个接一个地进行,而不是异步进行。 (除非它更聪明,并且忽略此错误的语法)。
一开始,请停止使用await
中的Promise.all
。
然后使用native Promises
instead of those from the axios http客户端。
Promise.all([count_ES_read(),mssqlQuery(mssqlQueryLessOneDay),
mssqlQuery(mssqlQueryLessEightHours), mssqlQuery(mssqlQueryTotal) ])
.then(function (resultES_read, mssqlLessOneDay, mssqlLessEightHours, mssqlTotal) {
req.storeValueKey ;
})
//编辑2
我发现您在理解async/await
和Promisses
时遇到了很大的问题。节点基于事件(例如获取结果)
非常泛化await
的意思是:“ 等待直到继续执行功能,直到获得结果。”和Promisses
:“ 创建一个管道,将处理then
并进一步处理指令。”
使用Promise.all()
的感觉是将Promisess放在那里。但是您正在使用await
const mssqlQuery = (query) => {
if (!query || query =="") {
throw new Error('Query for MSSQL was not defined!');
}
//I will not investigate whether you are doing well making a call with each request.
const conn = new sql.ConnectionPool(mssqlconfig);
const req = new sql.Request(conn);
return conn.connect().then(() => {
// Promise can return promise
let result = req.query(query);
conn.close();
return result;
});
}
const mssqlNoErrorQuery = (query) => {
return mssqlQuery(query).catch( e => {
return null; // no results
// OR fake resultset count
return {recordset:[{count:null}]};
/*
return e; // this will cause the error in the next stage
//to be treated as a correct situation.
// Next you should take care of it in such a way:
let res = await mssqlQuery(query);
if(res instanceof Error)
console.error('something wrong')
else
res.recordset[0].count
*/
});
}
let [res1, res2] = await Promise.all([
mssqlNoErrorQuery(query1),
mssqlQuery(query2).catch(e =>{/* local error handling */})
])
为了更好地理解整个想法,您应该使用以下代码进行一些实验:
function sleep(ms){
return new Promise(resolve=>{
setTimeout(resolve,ms)
})
}
function wait(msg) {
return new Promise(async(resolve) => {
console.log('START '+ msg)
await sleep(700)
console.log('finish '+ msg)
resolve(true)
} )
}
let fo = async () => {
Promise.all([await wait('d'), await wait('e'), await wait('f')]).then((c,d,e)=> {console.log('collect CDE')})
Promise.all([wait('a'),wait('b'),wait('c')]).then((c,d,e)=> {console.log('collect ABC')})
}
fo();
结果:
START d 12:22:06 PM
finish d 12:22:07 PM
START e 12:22:07 PM
finish e 12:22:07 PM
START f 12:22:08 PM
finish f 12:22:08 PM
START a 12:22:08 PM
START b 12:22:08 PM
START c 12:22:08 PM
collect CDE
finish a 12:22:09 PM
finish b 12:22:09 PM
finish c 12:22:09 PM
collect ABC
顺便说一句:您是否注意到在从c,d,e收集结果之前开始了过程a,b,c?
现在更改为:
let fo = async () => {
Promise.all([wait('a'),wait('b'),wait('c')]).then((c,d,e)=> {console.log('collect ABC')})
Promise.all([await wait('d'), await wait('e'), await wait('f')]).then((c,d,e)=> {console.log('collect CDE')})
}
结果:
START a
START b
START c
START d
finish a
finish b
finish c
finish d
collect ABC
START e
finish e
START f
finish f
collect CDE
如您在此处看到的,从1次呼叫开始所有承诺,从2次呼叫开始最合适