NodeJS 8.5+Express中async.each同步转异步的规范实现问询
async.each in Node.js 8.5 + Express Hey there! Let's get your code aligned with Node.js's asynchronous principles. First off, running heavy synchronous code inside async.each blocks the event loop—this hurts your Express app's ability to handle concurrent requests, which defeats the purpose of using async utilities in the first place. Let's walk through the right approaches:
1. Use Native Asynchronous APIs (Best Practice)
If the synchronous methods you're using have asynchronous counterparts (like fs.readFile instead of fs.readFileSync), switch to those. async.each is designed to work with callback-based async functions, so this is the cleanest approach.
Example:
const async = require('async'); const fs = require('fs'); async.each(objArray, (item, callback) => { // Switch logic based on item properties if (item.type === 'file') { // Async file operation fs.readFile(item.path, 'utf8', (err, data) => { if (err) return callback(err); // Pass error to the final handler // Process file data here callback(null); // Signal success for this item }); } else if (item.type === 'database') { // Async database query db.query('SELECT * FROM records WHERE id = ?', [item.id], (err, results) => { if (err) return callback(err); // Handle query results callback(null); }); } }, (err) => { if (err) { console.error('Processing failed:', err); return res.status(500).send('Oops, something went wrong!'); } console.log('All items processed successfully'); res.send('Done!'); });
2. Wrap Synchronous Code in Async Wrappers (When No Async API Exists)
If you have to use synchronous code, wrap it with setImmediate or process.nextTick to push the work to the next event loop iteration—this prevents blocking the event loop while processing all items. Don't forget to catch errors, since synchronous code can throw exceptions.
Example:
async.each(objArray, (item, callback) => { setImmediate(() => { try { let result; // Tailor sync logic to item properties if (item.type === 'calculation') { result = syncMathOperation(item.data); } else { result = syncDataTransform(item.raw); } // Process the result as needed callback(null); // No error, move to next item } catch (err) { callback(err); // Pass thrown error to the final handler } }); }, (err) => { if (err) console.error('Error processing items:', err); else console.log('All items handled'); });
3. Use Async/Await (Modern Alternative to async.each)
Node.js 8.5 introduced experimental support for async/await (you might need to run with the --harmony-async-await flag or use Babel). This makes your code more readable and avoids callback hell.
Parallel Processing (Similar to async.each):
async function processItems(objArray) { try { // Process all items in parallel with Promise.all await Promise.all(objArray.map(async (item) => { if (item.type === 'asyncTask') { await doAsyncWork(item); // Async function returning a promise } else { // Wrap sync code in a promise to make it awaitable await new Promise((resolve, reject) => { setImmediate(() => { try { doSyncWork(item); resolve(); } catch (err) { reject(err); } }); }); } })); res.send('All items processed successfully!'); } catch (err) { console.error('Processing failed:', err); res.status(500).send(err.message); } } // Call this function in your Express route processItems(objArray);
Serial Processing (Similar to async.eachSeries):
If you need to process items one after another (instead of in parallel), use a for...of loop with await:
async function processItemsSerially(objArray) { try { for (const item of objArray) { if (item.type === 'asyncTask') { await doAsyncWork(item); } else { await new Promise((resolve, reject) => { setImmediate(() => { try { doSyncWork(item); resolve(); } catch (err) { reject(err); } }); }); } } res.send('Items processed one by one successfully!'); } catch (err) { res.status(500).send('Serial processing failed: ' + err.message); } }
Key Takeaways
- Prioritize async APIs: Always use asynchronous versions of functions when available—this keeps your event loop free to handle other requests.
- Wrap sync code carefully: When you can't avoid sync code, use
setImmediateto prevent blocking. - Consider async/await: It's a more maintainable alternative to the
asyncmodule, especially as you scale your codebase.
内容的提问来源于stack exchange,提问作者pengz

