问题
I am running a Node+Express API that is working quite well, the only problem I have is when returning a complex query as a response, the variable to which I set the response to is not getting reset between requests.
It duplicates replies to the client such as replying 1, 2, 3 then the next reply replies 1, 2, 3, 1, 2, 3. So basically, it's concatenating data and not setting the allPosts
variable to null again.
Here is my code:
var allPosts = [];
chirprdb.allPosts = (userData) => {
return new Promise((resolve, reject) => {
userData.locations.forEach((location) =>{
pool.query('SELECT posts.post_id, posts.title, posts.description FROM posts_locations INNER JOIN posts on posts.post_id = posts_locations.post_id WHERE posts_locations.location_id = ?', location.location_id, (err, results) => {
if(err){
return reject(err);
}
// allPosts.push(results)
results.forEach((result) =>{
allPosts.push(result)
})
});
})
resolve(allPosts)
});
};
回答1:
The best way to program something like this is to use a promise interface on your database and then you can use promise-based tools for managing asynchronous operations.
The mysql2 module has a promise interface (that replaces the callback interface) and this function you have would look something like this:
const mysql = require('mysql2/promise');
// returns a promise that resolves with a
chirprdb.allPosts = (userData) => {
return Promise.all(usrData.locations.map(location => {
return pool.query('SELECT posts.post_id, posts.title, posts.description FROM posts_locations INNER JOIN posts on posts.post_id = posts_locations.post_id WHERE posts_locations.location_id = ?', location.location_id);
}));
}
But, I presume you need to change all your mysql programming over to the mysql2 promises interface.
There are also promise wrappers for the original mysql library such as https://www.npmjs.com/package/mysql-promise.
Your scheme does not work because you're calling resolve(allPosts)
BEFORE anything has been added to allPosts
and thus you're probably calling it again while it's still adding more things to allPosts
and thus you feel like it isn't empty. In any case, your current method is a timing disaster.
If you want to keep with the callback interface for mysql, then you have to implement some sort of counter that tells you when all your requests are done like this:
chirprdb.allPosts = (userData) => {
let allPosts = [];
let cntr = 0;
return new Promise((resolve, reject) => {
for (let i = 0; i < userData.locations.length; i++) {
let location = userData.locations[i];
pool.query('SELECT posts.post_id, posts.title, posts.description FROM posts_locations INNER JOIN posts on posts.post_id = posts_locations.post_id WHERE posts_locations.location_id = ?', location.location_id, (err, results) => {
if(err){
return reject(err);
}
++cntr;
allPosts[i] = results;
// if all queries done now
if (cntr === userData.locations.length) {
resolve(allPosts.flat());
}
});
})
});
};
回答2:
Just put allPosts
in new Promise
block.
来源:https://stackoverflow.com/questions/57701211/array-not-reseting-in-node-js