Are Generators Useless 2023?

Generators in JavaScript are not useless; they serve specific use cases where their unique abilities are beneficial. They can simplify certain problems, especially those that involve stateful iteration or lazy evaluation. While async/await has taken over many use cases that generators with Promises used to handle, generators still have their place. Here are some modern use cases where generators can be the preferred choice:

Custom Iterators: Generators provide a simple way to implement custom iterators. This is useful when you need to iterate over a sequence that isn't inherently an array or stream but can be represented as such.

Lazy Evaluation: If you have a potentially large set of data that you want to process one item at a time, without loading everything into memory, generators are a good fit. They allow you to work with each item individually and stop processing whenever you need to, without the overhead of processing the entire dataset.

Cooperative Multitasking: Generators can yield control of execution back to the calling code, allowing for complex multitasking scenarios where functions need to pause and resume based on the application's state.

State Machines: Generators can be used to implement finite state machines in a very readable way because the state can be maintained across yields within the generator function itself.

Control Flow for Asynchronous Code: While async/await handles most async patterns, generators can still be used for more complex control flows, especially when combined with coroutines libraries.

Complex Traversals: When traversing complex data structures, like trees or graphs, generators can provide an elegant solution. They allow you to yield each node as it's visited without the need for a callback or event system.

Pauseable Computations: Generators are suitable for computations that may need to pause, perhaps waiting for user input or other interactions before continuing.

Here's an example of using a generator for a custom iterable scenario:

function* idGenerator() {
  let id = 0;
  while (true) {
    yield id++;
  }
}

// Usage
const ids = idGenerator();
console.log(ids.next().value); // 0
console.log(ids.next().value); // 1
// ...etc. You can generate IDs on-demand without storing them.

In this scenario, the generator function idGenerator creates an endless supply of IDs that can be fetched one at a time, as needed, without storing an array of IDs.

It's essential to understand that generators are not a one-size-fits-all solution and should be used when their specific benefits align with the problem you are trying to solve. They can provide elegant and efficient solutions to problems involving iterative processes or lazy evaluation, which are still very relevant in 2023 and beyond.