Problem: Chain Multiple Decorators on a Service Method

easy
15 min
Combine two decorators—'withLogging' and 'withTiming'—to enhance an async function with both visibility and performance tracking.

Problem statement

You’re working with a simulated service that fetches user data asynchronously. The team wants to add logging for visibility and timing for performance monitoring—but the function itself can’t be changed. Each decorator adds one layer of behavior. We’ll need to compose them correctly so that logging and timing both work together without interfering.

Goal

Create two decorators:

  • withLogging(fn): Logs input arguments and the returned value.

  • withTiming(fn): Measures execution time and logs it.

Then, combine them in the same async function. The composed decorator should log arguments, output, and timing in the correct order.

Constraints

  • Do not modify the fetchUserData function.

  • Both decorators must be independent and composable.

  • You must call withTiming(withLogging(fetchUserData)) to layer them.

  • Do not use conditionals to merge behaviors.

If your [TIMER] log isn’t showing a function name, it’s because withLogging(fetchUserData) returns an anonymous wrapper function. When withTiming wraps it, the original name is lost. To fix this, use Object.defineProperty(wrappedFn, 'name', { value: fn.name }) to preserve the name for downstream decorators.

Sample output

The examples below illustrate what the output should look like:

const decoratedFetch = withTiming(withLogging(fetchUserData));
(async () => {
await decoratedFetch(101);
})();
/* Expected output (Timer may vary):
[LOG] Called with args: [101]
[LOG] Returned: { id: 101, name: 'Alice' }
[TIMER] fetchUserData took 121ms */

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Problem: Chain Multiple Decorators on a Service Method

easy
15 min
Combine two decorators—'withLogging' and 'withTiming'—to enhance an async function with both visibility and performance tracking.

Problem statement

You’re working with a simulated service that fetches user data asynchronously. The team wants to add logging for visibility and timing for performance monitoring—but the function itself can’t be changed. Each decorator adds one layer of behavior. We’ll need to compose them correctly so that logging and timing both work together without interfering.

Goal

Create two decorators:

  • withLogging(fn): Logs input arguments and the returned value.

  • withTiming(fn): Measures execution time and logs it.

Then, combine them in the same async function. The composed decorator should log arguments, output, and timing in the correct order.

Constraints

  • Do not modify the fetchUserData function.

  • Both decorators must be independent and composable.

  • You must call withTiming(withLogging(fetchUserData)) to layer them.

  • Do not use conditionals to merge behaviors.

If your [TIMER] log isn’t showing a function name, it’s because withLogging(fetchUserData) returns an anonymous wrapper function. When withTiming wraps it, the original name is lost. To fix this, use Object.defineProperty(wrappedFn, 'name', { value: fn.name }) to preserve the name for downstream decorators.

Sample output

The examples below illustrate what the output should look like:

const decoratedFetch = withTiming(withLogging(fetchUserData));
(async () => {
await decoratedFetch(101);
})();
/* Expected output (Timer may vary):
[LOG] Called with args: [101]
[LOG] Returned: { id: 101, name: 'Alice' }
[TIMER] fetchUserData took 121ms */

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Node.js
// Simulated async service
async function fetchUserData(id) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id, name: 'Alice' });
}, 120);
});
}
// Your code here
// Example usage
const decoratedFetch = withTiming(withLogging(fetchUserData));
(async () => {
await decoratedFetch(101);
})();
/* Expected output:
[LOG] Called with args: [101]
[LOG] Returned: { id: 101, name: 'Alice' }
[TIMER] fetchUserData took 121ms */