问题
I am coming from php background where sql queries are blocking.
My usual setup is to make a try, catch
block to handle any possible errors that might happen during table updating. I wanted to transfer this logic to nodejs, but it's asynchronous nature is making this troublesome. Take a look at example code:
var httpServer = Https.createServer(httpsOptions, function (request, response) {
try {
//many queries in if-else, switch statements
if(something){
mysqlConnection.query(query,[],function(err, result){});
}else{
//many queries will follow
if(somethingelse){
mysqlConnection.query(query2,[],function(err, result){});
}else{
mysqlConnection.query(query3,[],function(err, result){});
if(andsoon){}
}
}
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Got it.");
console.log("Response successful");
}catch(error){
console.error(error);
response.writeHead(400, { "Content-Type": "text/plain" });
response.end("Error.");
}
}).listen(8000);
So, response.end()
will trigger before the query executes so I send the message before I know if the query was successful. I could wrap the response.end()
code in callback, but there are MANY queries that are executing, so now I have to track how many were executed so far. Things get worse, 1 if-else control flow requires just 1 query, some other requires 10 so there is crazy overhead with tracking when the code is completed.
This all can't be the optimal workflow. What do you do when you have a complex query system and you want to send response only after all queries have executed(or failed)?
回答1:
You've put null callbacks from your .query invocations. That's your problem.
mysqlConnection.query(query,[],function(err, result){});
xxxxxxxxxxxxxxxxxxxxxxxx
Javascript goes on to run the next statement after the one shown immediately without waiting for the query to finish. You know the query is complete (or it hit an error) only when the .query method invokes your callback function.
So, you need to do something like this instead.
mysqlConnection.query(query,[],function(err, result){
if (err) throw Error(err);
//many queries will follow
if(somethingelse){
...
}
});
A sequence of queries like you need ends up with an absurdly deeply nested set of callback functions. But don't despair: Javascript's Promise pattern works around this for you and gives you clean code. Use npm's promise-mysql package. And write code like this.
mysqlConnection.query(query,[])
.then (function(mySqlConnection) {
if (somethingelse)
return mysqlConnection.query(query2,[])
else
return mysqlConnection.query(query3,[])
})
.then (function(mySqlConnection) {
return mysqlConnection.query(query4,[])
})
.then (function(mySqlConnection) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Got it.");
})
.catch (function(err)) {
/* failure somewhere ! */
});
You have a series of then functions, with a catch at the end. The Promise subsystem hides all the callback invocation for you, organizing it this way instead. (Notice that I did not debug this sample code.)
You must figure out this Promise stuff to program sql / nodejs successfully. It's counterintuitive at first (at least it was for me when I was learning it). But it's worth your effort. Pro tip: if you're stepping through this kind of code in a debugger, use Step Into liberally.
来源:https://stackoverflow.com/questions/54346143/catch-mysql-errors-before-sending-http-response