Hone logo
Hone
Problems

Implementing a Macro Task Runner in Vue.js with TypeScript

This challenge focuses on building a reusable macro task runner within a Vue.js application. Macro tasks, in this context, are sequences of asynchronous operations that need to be executed in a specific order, ensuring dependencies are met and avoiding race conditions. This is useful for complex workflows, data fetching sequences, or any scenario where you need to orchestrate multiple asynchronous actions.

Problem Description

You are tasked with creating a MacroTaskRunner component in Vue.js that allows users to define and execute a series of asynchronous tasks. Each task should accept a context object that can be passed between tasks, allowing them to share data and state. The component should provide a method to add tasks, a method to execute the macro, and a mechanism to track the progress and any errors that occur during execution.

Key Requirements:

  • Task Definition: Tasks should be defined as functions that accept a context object and return a Promise.
  • Context Propagation: The context object should be passed to each task in the sequence. The result of each task should be added to the context, allowing subsequent tasks to access it.
  • Sequential Execution: Tasks must be executed sequentially, waiting for each task to complete before starting the next.
  • Error Handling: If any task throws an error, the macro execution should stop, and the error should be reported.
  • Progress Tracking: The component should emit events to indicate the start, completion, and any errors during the macro execution.
  • Cancellation (Optional): While not strictly required, consider how you might add a cancellation mechanism to stop a running macro.

Expected Behavior:

  1. The component should maintain an array of tasks.
  2. The addTask method should add a new task function to the array.
  3. The runMacro method should execute the tasks sequentially, passing the initial context.
  4. The component should emit a start event before starting the macro.
  5. The component should emit a complete event when all tasks have completed successfully.
  6. The component should emit an error event if any task throws an error.
  7. The context object should be updated with the results of each task.

Edge Cases to Consider:

  • Empty task array: What should happen if runMacro is called with an empty task array?
  • Tasks that return non-Promise values: How should the component handle tasks that don't return a Promise? (Consider treating them as immediately resolved Promises).
  • Tasks that throw synchronous errors: How should these be handled differently from asynchronous errors?
  • Context object immutability: Consider whether the context object should be mutated or copied at each step to avoid unintended side effects.

Examples

Example 1:

Input:
tasks: [
  () => new Promise(resolve => setTimeout(() => resolve({ step1: 'data1' }), 500)),
  (context) => new Promise(resolve => setTimeout(() => resolve({ step2: 'data2', combined: context.step1 + ' and more' }), 300)),
]
initialContext: {}
Output:
{ step1: 'data1', step2: 'data2', combined: 'data1 and more' }
Explanation: The first task resolves after 500ms, adding { step1: 'data1' } to the context. The second task resolves after 300ms, adding { step2: 'data2', combined: 'data1 and more' } to the context, using the value from step1.

Example 2:

Input:
tasks: [
  () => new Promise(resolve => setTimeout(() => resolve({ step1: 'data1' }), 500)),
  (context) => new Promise(resolve => setTimeout(() => { throw new Error('Task failed'); }, 300)),
]
initialContext: {}
Output:
Error: Task failed
Explanation: The first task resolves. The second task throws an error, causing the macro to stop and emit an error event.

Example 3: (Edge Case)

Input:
tasks: []
initialContext: {}
Output:
(No tasks executed, emits 'start' and then 'complete' events immediately)
Explanation:  The task array is empty. The macro starts and completes immediately without executing any tasks.

Constraints

  • The component must be written in Vue.js using TypeScript.
  • The component should be reusable and configurable.
  • The execution time of the macro should be reasonable for typical use cases. Avoid unnecessary overhead.
  • The component should handle errors gracefully and provide informative error messages.
  • The component should emit appropriate events for progress tracking.

Notes

  • Consider using async/await for cleaner asynchronous code.
  • Think about how to manage the context object effectively to avoid unintended side effects.
  • You can use Vue's reactivity system to track the progress of the macro.
  • Focus on creating a well-structured and maintainable component.
  • The initial context is passed as an argument to runMacro.
  • The component should expose a method to add tasks dynamically.
Loading editor...
typescript