Skip to content

Latest commit

 

History

History
117 lines (84 loc) · 5.18 KB

File metadata and controls

117 lines (84 loc) · 5.18 KB

Generators in JavaScript are special kinds of functions that can be paused and resumed, allowing other code to run in the meantime. They are defined using the function* syntax.

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

const gen = idGenerator();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2

idGenerator is a generator that produces a new id each time its next method is called. You can manually control the iteration of a generator in JavaScript by using the next() method on the generator object. Each call to next() will return an object with two properties: value (the yielded value) and done (a boolean indicating whether the generator is done yielding values).

You can iterate over the values produced by a generator in JavaScript using a for...of loop. Here's an example:

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

const gen = idGenerator();

for (let value of gen) {
  console.log(value); // logs 0, then 1, then 2
}

The for...of loop automatically calls next() on the generator object and terminates when it encounters a done property set to true in the object returned by next().

You can pass arguments to a generator function in JavaScript just like you would with a regular function. When the generator function is invoked, the arguments are passed in. Here's an example:

function* range(start, end) {
  while (start <= end) {
    yield start++;
  }
}

const numbers = range(1, 5);

for (let number of numbers) {
  console.log(number); // logs 1, then 2, then 3, then 4, then 5
}

The range generator function takes two arguments, start and end. These arguments are used to determine the range of numbers that the generator produces.

Pros:

  • Generators allow you to write asynchronous code that looks synchronous, which can make it easier to understand and reason about.
  • They can be used to create iterable objects.
  • They can be used to manage flow control, making it easier to write non-blocking code.

Cons:

  • Generators can make code harder to understand for developers who are not familiar with them, as the flow of execution is not as straightforward as with regular functions.
  • Error handling can be tricky with generators, as errors can be thrown at any point in the generator when it is resumed.
  • They are not as widely supported as other JavaScript features, particularly in older browsers.

Use cases

  1. Asynchronous Programming: Generators can be used to write asynchronous code in a synchronous manner, making it easier to read and understand. This is particularly useful when dealing with Promise or async/await .

  2. Control Flow Management: Generators can be used to manage control flow in your applications. For example, you can use a generator to pause and resume execution as needed.

  3. Implementing Iterators: Generators return iterator objects and can be used to simplify the creation of objects that conform to the iteration protocols. An iterator is an object that provides a next() method which returns the next item in the sequence. This method returns an object with two properties: value and done. Here's an example of an iterator:

const array = ['a', 'b', 'c'];
const iterator = array[Symbol.iterator]();

console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
  1. Producing a Sequence of Values: If you need to generate a sequence of values according to a certain rule, a generator can be a good choice. For example, generating a sequence of unique identifiers, Fibonacci numbers, etc.

  2. Lazy Evaluation: Generators can be used to implement lazy evaluation in JavaScript. Lazy evaluation is a technique where the evaluation of an expression is delayed until its value is needed. This can be useful when dealing with large data sets or infinite sequences.

Async generators

Async generators are a combination of async functions and generators. They allow you to yield Promises and use for await...of to iterate over them.

Here's an example of an async generator:

async function* asyncGenerator() {
  let i = 0;
  while (i < 3) {
    yield new Promise((resolve) => setTimeout(() => resolve(i++), 1000));
  }
}

(async function() {
  for await (let value of asyncGenerator()) {
    console.log(value); // logs 0, then 1, then 2 with a delay of 1 second between each log
  }
})();

In this example, asyncGenerator is an async generator that yields a new Promise each time it's iterated over. The Promise resolves to a value after a delay of 1 second. The for await...of loop is used to iterate over the async generator, automatically awaiting each Promise before proceeding to the next iteration.

Remember, while generators can be powerful, they also add complexity to your code. It's important to use them judiciously and only when their benefits outweigh the added complexity.