Today I Learned - Rocky Kev

TIL use-cases for Generators in Javascript

POSTED ON:

TAGS:

This is a generator.

The function* declaration (function keyword followed by an asterisk) defines a generator function, which returns a Generator object.

via the MDN


function* greeter() {
yield 'Hi';
yield 'How are you?';
yield 'Bye';
}

const greet = greeter();

console.log(greet.next().value);
// 'Hi'
console.log(greet.next().value);
// 'How are you?'
console.log(greet.next().value);
// 'Bye'
console.log(greet.next().value);
// undefined

How does it work?

Use Cases

via Use-Cases For JavaScript Generators

1 - Throttling a function

export function * throttle(func, time) {
let timerID = null;
function throttled(arg) {
clearTimeout(timerID);
timerID = setTimeout(func.bind(window, arg), time);
}
while(true) throttled(yield);
}

export class GeneratorThrottle {

constuctor() {};

start = () => {
thr = throttle(console.log, 3000);
thr.next('');
};

toString = () => {
console.log(throttle);
console.log('start =', this.start);
};
};

A state machine:


export class ContentStateMachine {
_content;
_default;
_statePatterns;
_returnState;
_changeAlgorithm;

_machine;

constructor(settings) {
this._content = settings.content;
this._default = settings.defaultIndex;
this._statePatterns = settings.statePatterns;
this._returnState = settings.returnState;
this._changeAlgorithm = settings.changeAlgorithm;

const machineSettings = {
'content': this._content,
'defaultIndex': this._default,
'statePatterns': this._statePatterns,
'returnState': this._returnState
};
this._machine = this.stateMachine(machineSettings);
return this._machine;
};

stateMachine = function * stateMachine(settings) {
const content = settings.content;
const defaultIndex = settings.defaultIndex;
const statePatterns = settings.statePatterns;
const returnState = settings.returnState;

let currentIndex = defaultIndex;
while (currentIndex >= 0 && currentIndex < content.length) {
if (this._changeAlgorithm) {
const states = returnState(content, currentIndex);
this._changeAlgorithm(states, currentIndex);
}
const changeType = yield returnState(content, currentIndex);
currentIndex = statePatterns[changeType](content, currentIndex);
}
};
}

Some more use-cases:

Via EmNudge

I had to find all people who have commented on issues at a particular GitHub repo. GitHub's rest API provides us with an endpoint that can list issue comments. With each page having a few results, in order to find all the commentors, we have to traverse all the pages. Now we can do this in a single run, and then show user the results, which will take really really long time of user seeing nothing (on a repo with 250 pages, it took 5-6 min). What can be better for user experience is to keep emitting unique commentors as we find them, hence creating a streamed output so user knows things are really in progress and not broken.

via Sid Vishnoi

The original reference: A Collection of JavaScript Tips Based on Common Areas of Confusion or Misunderstanding

and this:

// promise-based fetch
function fetchJson(url) {
return fetch(url)
.then(request => request.text())
.then(text => {
return JSON.parse(text);
})
.catch(error => {
console.log(`ERROR: ${error.stack}`);
});
}

// one with a generator and the co library
// https://github.com/tj/co

const fetchJson = co.wrap(function* (url) {
try {
let request = yield fetch(url);
let text = yield request.text();
return JSON.parse(text);
}
catch (error) {
console.log(`ERROR: ${error.stack}`);
}
});

via Exploring ES6


Related TILs

Tagged:

TIL not using try/catch block with promises for error catching

You shouldn't use a try/catch block inside the Promise Definition. Your promise is already doing that.

TIL using proxies for reactivity

A Proxy let you detect when someone gets, sets, or updates a property on an object, and run code when they do. But why? This usecase -- when you add/update the object, it also updates localStorage!

TIL the difference between partial application and currying

Partial application transforms a function into another function with smaller set of arguments. Currying creates nesting functions according to the number of the arguments of the function. Each function receives an argument.