Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ECMA6 - Use of Generator Function in JavaScript

Its been a few days that I got to learn about Generator functions in JavaScript which are introduced in ES6 version.

There were various places generators were explained but what seems too intriguing for me is the fact that everywhere it is said that

A generator function is a way to write async code synchronously.

The question that I want to raise is "Why is there so much need to introduce a completely different programming strategy just for the sake of it?"

I understand the async nature of the JS code makes it difficult for a newbie to understand and debug the code but does it require a complete change in coding style altogether?

I maybe wrong or not completely understanding the concept behind its introduction but being inquisitive about it all is what compelled me to ask this question.

like image 544
invincibleDudess Avatar asked Jan 05 '16 05:01

invincibleDudess


People also ask

What is the use of generator function in JavaScript?

Generator functions provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function whose execution is not continuous. Generator functions are written using the function* syntax. When called, generator functions do not initially execute their code.

When should we use generators in ES6?

In a normal function, there is only one entry point: the invocation of the function itself. A generator allows you to pause the execution of a function and resume it later. Generators are useful when dealing with iterators and can simplify the asynchronous nature of Javascript.

Why generator function is used in Saga?

Sagas are implemented as Generator functions that yield objects to the redux-saga middleware. The yielded objects are a kind of instruction to be interpreted by the middleware. When a Promise is yielded to the middleware, the middleware will suspend the Saga until the Promise completes.

What are generator function in JavaScript How are they different from normal function?

A Generator function returns us an iterator, which can be used to stop the function in the middle, do something, and then resume it whenever. A normal function starts executing and returns when the function completes, but a Generator function can be stopped any number of times and resumed later.


1 Answers

Because closures are less convenient for simple iteration; simplifying syntax for reasonably common tasks can be worth it, even if the language supported the same pattern before. Just compare:

function chain() {
    var args = Array.from(arguments);
    return function() {
        if (args.length === 0) return undefined; // Or some other sentinel
        var nextval = args[0].shift(); // Destructive to avoid copies or more closure vars
        if (args[0].length === 0) args.shift();
        return nextval;
    };
}
var x;
// a, b and c must be indexable, e.g. Arrays; we can't handle other closures without
// requiring some API specific protocol for generation
for (var nextchain = chain(a, b, c); (x = nextchain()) !== undefined;) {
    // do stuff with current value
}

to:

function* chain() {
    for (var i = 0; i < arguments.length; ++i)
        yield* arguments[i];
}
// a, b and c can be any iterable object; yield* can handle
// strings, Arrays, other generators, etc., all with no special handling
for (var x of chain(a, b, c)) {
    // do stuff with current value
}

Sure, the savings in lines of code aren't incredible. It's mostly just reducing boilerplate and unnecessary names, removing the need to deal with closures for simple cases, and with the for...of syntax, providing a common mechanism to iterate arbitrary iterable things, rather than requiring the user to explicitly construct the initial closure and advance it by name. But if the pattern is common enough, that's useful enough.

As noted in comments, a, b, c must be Array-like for the closure based approach (or you'd use a different closure based approach where the writer of chain imposes arbitrary requirements on stuff passed to it, with special cases for Array-like stuff vs. generator-like closures) and processing is destructive (you'd need to add more closure state or make copies to make it non-destructive, making it more complex or slower); for the generator-based approach with yield*, no special cases required. This makes generators composable without complex specs; they can build on one another easily.

like image 66
ShadowRanger Avatar answered Oct 04 '22 10:10

ShadowRanger