JavaScript中如何在循环执行完毕后才调用回调函数?
Solution: Ensure Callback Runs Only After All Async Queries Complete
Hey there! The core issue with your current code is that con.query is an asynchronous function—your loop will finish running long before all the database queries have completed. That means if you just tried to call callback right after the loop, it would fire before any of the query results are ready.
Here's how to fix this by using Promises and Promise.all() to wait for all asynchronous operations to finish first:
function insertIntoCacheRange(userID, from, to, callback){ const dataRanges = []; // Create an array to hold all our query promises const queryPromises = []; for(let pointer = from, index = parseInt(from) + 1800 ; index < to; pointer += 1800, index += 1800){ // Wrap each query in a Promise const queryPromise = new Promise((resolve, reject) => { const sqlSelect = "SELECT count(*) as count FROM sensordata WHERE sensorid = ? AND time >= ? AND time < ?"; con.query(sqlSelect, [userID, pointer, index], function(err, result){ if(err) { // Reject the promise if there's an error return reject(err); } // Parse the result and resolve the promise with the data const count = JSON.parse(JSON.stringify(result))[0].count; dataRanges.push({ pointer, index, count }); // Store the result if needed resolve(count); }); }); queryPromises.push(queryPromise); } // Wait for all promises to resolve (or any to reject) Promise.all(queryPromises) .then(() => { // All queries are done—call the callback callback(null, dataRanges); // Pass null for error, plus any collected data }) .catch((err) => { // If any query failed, call callback with the error callback(err); }); }
Key Changes Explained:
- Promisify the Queries: Each database query is wrapped in a
Promise, which lets us track when it completes successfully (resolve) or fails (reject). - Collect Promises: We add every query promise to an array so we can wait for all of them at once.
Promise.all(): This method waits until all promises in the array have resolved. Once they do, we safely call yourcallback—knowing every query has finished.- Error Handling: We added a
.catch()to handle any database errors, ensuring the callback gets notified if something goes wrong.
Alternative: Using Async/Await (Cleaner Syntax)
If you prefer modern async/await syntax, here's a version that's easier to read:
async function insertIntoCacheRange(userID, from, to, callback){ try { const dataRanges = []; const queryPromises = []; for(let pointer = from, index = parseInt(from) + 1800 ; index < to; pointer += 1800, index += 1800){ const queryPromise = new Promise((resolve, reject) => { const sqlSelect = "SELECT count(*) as count FROM sensordata WHERE sensorid = ? AND time >= ? AND time < ?"; con.query(sqlSelect, [userID, pointer, index], function(err, result){ if(err) return reject(err); const count = JSON.parse(JSON.stringify(result))[0].count; dataRanges.push({ pointer, index, count }); resolve(count); }); }); queryPromises.push(queryPromise); } // Wait for all queries to finish await Promise.all(queryPromises); // Call callback once everything is done callback(null, dataRanges); } catch(err) { callback(err); } }
Either version ensures your callback only runs after every single database query has completed (successfully or with an error).
内容的提问来源于stack exchange,提问作者Sergio Barbero
相关产品推荐
相关产品推荐

