About generators in javascript es6 and why it’s not necessary to study them

Original author: Ben Garrison
  • Transfer
With the growing popularity of the async / await construction, the interest in its internal mechanisms is growing. Having rummaged through the Internet, it is easy to find out that async / await is based on well-known promises, and generators, which are much less famous and popular. The material, the translation of which we are publishing today, is devoted to generators. Namely, here we will talk about how they work, and how they, together with promises, are used in the depths of the async / await construction. The author of this article says that generators, for the sake of their practical application, are not necessary to master. In addition, he notes that he expects that the reader is a little versed in promises.





Iterators and Generators


In JavaScript, starting with the release of the ES6 standard, several new features have appeared that are aimed at simplifying work with asynchronous data streams and collections. Iterators and generators fall into this category .

A remarkable feature of iterators is that they provide the means to access the elements of collections one at a time, while still allowing you to track the identifier of the current element.

functionmakeIterator(array) {
  var nextIndex = 0;
  console.log("nextIndex =>", nextIndex);
  return {
    next: function() {
      return nextIndex < array.length
        ? { value: array[nextIndex++], done: false }
        : { done: true };
    }
  };
}
var it = makeIterator(["simple", "iterator"]);
console.log(it.next()); // {value: 'simple, done: false}console.log(it.next()); // {value: 'iterator, done: false}console.log(it.next()); // {done: true}

Above, we pass to the function a makeIterator()small array containing a couple of elements, and then we pass through it with an iterator, calling the method it.next(). Pay attention to the comments demonstrating the results obtained using the iterator.

Now let's talk about the generators. Generators are functions that work as iterator factories. Consider a simple example, and then talk about two mechanisms related to generators.

function* sample() {
  yield"simple";
  yield"generator";
}
var it = sample();
console.log(it.next()); // {value: 'simple, done: false}console.log(it.next()); // {value: 'generator, done: false}console.log(it.next()); // {value: undefined, done: true}

Pay attention to the asterisk in the function declaration. This indicates that this function is a generator. Also, take a look at the keyword yield. It pauses the execution of the function and returns some value. Actually, these two features are the very two mechanisms that we talked about above:

  • A generator function is a function declared using an asterisk near a keyword functionor around a function name.
  • A generator iterator is created when a generator function is called.

In general, the above example demonstrates the work of a factory function that generates iterators.

Now that we have the basics, let's talk about more interesting things. Iterators and generators can exchange data in two directions. Namely, generators, using a keyword yield, can return values ​​to iterators, however, iterators can send data to generators using the method iterator.next('someValue'). Here's what it looks like.

function* favBeer() {
  const reply = yield"What is your favorite type of beer?";
  console.log(reply);
  if (reply !== "ipa") return"No soup for you!";
  return"OK, soup.";
}
{
  const it = favBeer();
  const q = it.next().value; // Итератор задаёт вопрос
  console.log(q);
  const a = it.next("lager").value; // Получен ответ на вопрос
  console.log(a);
}
// What is your favorite beer?// lager// No soup for you!
{
  const it = favBeer();
  const q = it.next().value; // Итератор задаёт вопрос
  console.log(q);
  const a = it.next("ipa").value; // получен ответ на вопрос
  console.log(a);
}
// What is your favorite been?// ipa// OK, soup.

Generators and promises


Now we can talk about how generators and promises form the basis of the async / await construction. Imagine that instead of returning, using a keyword yield, certain values, the generator returns promises. In this situation, the generator can be wrapped in a function that will wait for promise resolution and return the value of the promise to the generator in the method .next(), as shown in the previous example. There is a popular library, co , which performs just such actions. It looks like this:

co(function* doStuff(){
  var result - yield someAsyncMethod();
  var another = yield anotherAsyncFunction();
});

Results


According to the author of this material, JS developers need to know how generators work, only to understand the features of the internal structure of the async / await structure. But you should not use them directly in your own code. Generators injected into JavaScript the ability to suspend the execution of the function and return to it when (and if) the developer deems it necessary. Until now, we, working with JS-functions, expected that they, being called, are simply executed from start to finish. The ability to suspend them is already something new, but this functionality is conveniently implemented in the async / await construction.

With this opinion, of course, it is possible to argue. For example, one of the arguments in favor of generators is that knowledge of how they work is useful for debugging code with async / await, since generators are hidden inside this construct. However, the author of the material believes that it is, nevertheless, something other than the use of generators in your own code.

Dear readers! What do you think about generators? Maybe you know some options for their use, which justify their direct use in the code of JS-projects?

The royal promo code for a 10% discount on our virtual servers:


Also popular now: