Hone logo
Hone
Problems

Asynchronous Data Streaming with Generators

Asynchronous operations are fundamental to modern JavaScript, especially when dealing with network requests or large datasets. Generators provide a powerful way to create iterators, and combining them with async/await allows for elegant and efficient asynchronous data streaming. This challenge asks you to implement a function that uses a generator to asynchronously yield data chunks, simulating a stream of data from an external source.

Problem Description

You need to create an asyncGeneratorStream function that takes an asynchronous data source (a function that returns a Promise resolving to an array of data) and a chunk size as input. The function should return an asynchronous generator that yields data in chunks of the specified size. The generator should call the provided asynchronous data source once and then yield the data in chunks. The generator should handle potential errors from the data source gracefully, re-throwing them.

Key Requirements:

  • Asynchronous Data Source: The function must accept a function that returns a Promise. This Promise should resolve to an array of data.
  • Chunking: The generator must yield data in chunks of the specified chunkSize.
  • Asynchronous Yielding: The yield keyword must be used within the generator to asynchronously provide data chunks.
  • Error Handling: If the asynchronous data source throws an error, the generator must re-throw that error.
  • Single Execution: The data source function should be called only once.

Expected Behavior:

The asyncGeneratorStream function should return an asynchronous generator. When iterated over (e.g., using a for...await...of loop), the generator should yield chunks of data until all data has been processed.

Edge Cases to Consider:

  • Empty Data Source: The data source might return an empty array. The generator should not yield any chunks in this case.
  • Data Source Errors: The data source might reject its Promise, indicating an error.
  • Chunk Size of 0 or Negative: Handle invalid chunk sizes gracefully (e.g., by throwing an error or defaulting to a reasonable chunk size).
  • Data Source Returns Non-Array: The data source might return a Promise that resolves to something other than an array. Handle this gracefully (e.g., by throwing an error).

Examples

Example 1:

Input:
asyncDataSource = async () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
chunkSize = 3;

Output:
(Iterating over the generator yields):
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]
Explanation: The data is split into chunks of 3, with the last chunk containing the remaining elements.

Example 2:

Input:
asyncDataSource = async () => [];
chunkSize = 2;

Output:
(Iterating over the generator yields nothing)
Explanation: The data source returns an empty array, so no chunks are yielded.

Example 3:

Input:
asyncDataSource = async () => { throw new Error("Data source failed"); };
chunkSize = 2;

Output:
(Iterating over the generator throws an error):
Error: Data source failed
Explanation: The data source throws an error, which is re-thrown by the generator.

Constraints

  • chunkSize must be a positive integer. If it's not, throw a TypeError.
  • The asyncDataSource function must return a Promise that resolves to an array. If it doesn't, throw a TypeError.
  • The data within the array returned by asyncDataSource can be of any type.
  • The generator should be efficient and avoid unnecessary memory allocations.

Notes

  • Consider using async/await within the generator function to handle the asynchronous data source.
  • The generator should not store the entire dataset in memory at once; it should process it in chunks.
  • Think about how to handle the last chunk, which might be smaller than the specified chunkSize.
  • Error handling is crucial for robust asynchronous code. Ensure that errors from the data source are propagated correctly.
  • The goal is to create a clean and readable solution that effectively demonstrates the use of generators for asynchronous data streaming.
Loading editor...
javascript