Node.js Async Patterns & Error Handling 4 — Questions and Answers
Question 1: What is the difference between `process.nextTick()` and `setImmediate()` in Node.js?
- `process.nextTick()` fires after I/O callbacks; `setImmediate()` fires before them
- `process.nextTick()` fires at the end of the current operation before I/O; `setImmediate()` fires in the check phase after I/O (Correct answer)
- They execute in the same phase of the event loop
- `setImmediate()` is faster than `process.nextTick()`
Correct answer: `process.nextTick()` fires at the end of the current operation before I/O; `setImmediate()` fires in the check phase after I/O
`process.nextTick()` callbacks run before any I/O or timers after the current operation, while `setImmediate()` runs in the check phase after I/O events.
Question 2: What does `util.callbackify()` do in Node.js?
- Converts callback functions into async functions
- Converts an async/Promise-returning function into a Node.js callback-style function (Correct answer)
- Validates that a callback follows the error-first convention
- Removes callbacks from EventEmitter listeners
Correct answer: Converts an async/Promise-returning function into a Node.js callback-style function
`util.callbackify()` takes an async function and returns a function that calls a Node.js-style (err, result) callback instead of returning a promise.
Question 3: Which pattern allows you to avoid uncaught errors when using `async` functions as Express route handlers?
- Wrap the handler in try/catch and call next(err) on error (Correct answer)
- Use process.on('uncaughtException') in the route
- Use async IIFE inside the route function
- Express automatically catches errors in async handlers
Correct answer: Wrap the handler in try/catch and call next(err) on error
Express does not catch async errors automatically, so you must wrap with try/catch and pass errors to `next(err)` to trigger error-handling middleware.
Question 4: What is 'backpressure' in Node.js streams?
- An error that occurs when too many event listeners are added
- The mechanism where a writable stream signals a readable stream to slow down data production (Correct answer)
- A memory leak caused by unresolved promises
- CPU pressure from synchronous blocking operations
Correct answer: The mechanism where a writable stream signals a readable stream to slow down data production
Backpressure occurs when a writable stream's buffer is full; it signals upstream readable streams to pause so the system doesn't run out of memory.
Question 5: What is a common pitfall when using `async` functions inside `Array.prototype.forEach()`?
- forEach does not support arrow functions
- Errors thrown inside the async callback are silently lost and forEach doesn't await the callbacks (Correct answer)
- forEach runs callbacks synchronously which blocks the event loop
- The array index is incorrect inside async callbacks
Correct answer: Errors thrown inside the async callback are silently lost and forEach doesn't await the callbacks
`forEach` ignores returned promises, so async callbacks run without being awaited, and any rejections become unhandled promise rejections.
Question 6: How does Node.js handle an `async` function that throws an error and is not awaited?
- The error crashes the process immediately
- The error becomes an unhandled promise rejection (Correct answer)
- Node.js automatically logs the error and continues
- The error is passed to the nearest try/catch block
Correct answer: The error becomes an unhandled promise rejection
If an async function throws (or rejects) and the call site doesn't await or attach `.catch()`, the rejection is unhandled and triggers the `unhandledRejection` event.
Question 7: What is the output of this code? ``` async function main() { throw new Error('oops'); } main().catch(e => console.log(e.message)); ```
- Uncaught Error: oops
- oops (Correct answer)
- undefined
- The program exits with code 1
Correct answer: oops
The async function rejects with 'oops', and the `.catch()` handler receives the error object and logs its message.
What is the difference between `process.nextTick()` and `setImmediate()` in Node.js?