Skip to content

Instantly share code, notes, and snippets.

@suityou01
Created October 30, 2020 17:24
Show Gist options
  • Save suityou01/f9a451ceb544381437aa6a58ce2dd923 to your computer and use it in GitHub Desktop.
Save suityou01/f9a451ceb544381437aa6a58ce2dd923 to your computer and use it in GitHub Desktop.
Coroutines
/*
Types of function in javascript
1. Regular function - function f () {}
2. Anonymous function - () => {}
3. Asynchronous function - async function f () {}
4. Asynchronous anonymous function async () {}
5. Generator function - function* f () {}
6. Asyncronous generator function async function* f (){}
*/
/* What the f? */
/*
function* f(){
yield 1;
yield 2;
yield 3;
}
console.log( f() );
let caller = f();
console.log(caller.next());
console.log(caller.next());
console.log(caller.next());
console.log(caller.next());
*/
/*Generator can be used for data generation*/
/*
function* serial(){
let n=0;
while(true){
yield n++;
}
}
let s=serial();
let t=serial();
console.log(s.next());
console.log(s.next());
console.log(s.next());
console.log(t.next()); //A reference to a generator function is also an instance of that generator function
*/
/*Generators can be iterated using regular higher order array functions*/
/*
function* finite_serial(){
for(let i=0; i<5; i++){
yield i;
}
}
let serials = [...finite_serial()];
console.log(serials);
*/
/*It is a pull based mechanism. Also known as imperative event based.*/
/*This means the caller calls the tune of when the next value is called*/
/*This is useful for streaming for example*/
/*
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
let q = [ 'apple', 'banana', 'pear'];
function* feeder(){
while(q.length===0){
q.push('french fry');
console.log("Fed a french fry to the hippo");
}
sleep(2000);
yield* eater();
}
function* eater(){
while(q.length>0){
console.log(`Yum I just ate a ${q.pop()} `);
}
sleep(2000);
yield* feeder();
}
let hungryhippo = eater();
hungryhippo.next();
*/
/*Generators can be asynchronous. That means the iterator is a promise*/
/*
async function* awaitme(){
yield "Hello";
yield "World";
}
let f = awaitme();
f.next()
.then(data => console.log(data)) //Prints Hello
f.next()
.then(data => console.log(data)) //Prints World
let p = awaitme();
console.log(p.next()); //Prints Promise
*/
/*Recreate python's range function!*/
/*
x = range(6)
for n in x:
print(n)
*/
/*
const range = (end, start = 0, step = 1) => {
function* generateRange() {
let x = start - step;
while(x < end - step) yield x += step;
}
return {
[Symbol.iterator]: generateRange
};
}
console.log([...range(50)].map((item)=>{
item2 = {};
item2.firstName = "Fred",
item2.lastName = "Bloggs"
return item2;
}));
console.log([...range(7)]);
console.log("*********");
for (let i of range(6)) console.log(i);
console.log("*********");
[...range(7)].forEach(r=>console.log(r));
console.log("*********");
*/
/*A practical use case for an async generator*/
/*A file downloader*/
/*
function task(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
function longtask(){
return task(5000);
}
async function* download_documents(total) {
for(let i=1; i<=total; i++){
longtask();
yield { processed: i, total };
}
}
(async () => {
for await (const val of download_documents(5)) {
// Prints "1 / 5", "2 / 5", "3 / 5", etc.
console.log(`${val.processed} / ${val.total}`);
}
})();
console.log("Other stuff is happening while the docs are 'downloading'");
*/
//***NB The await keyword is abstracting the 'then' callback***
/*
Best ever description of abstraction, Richard Feyman
In a computer's arithmetic logic unit, it can do simple binary addition
So that two binary numbers can be added like so
1101 } Summand
0011 } Summand
------
10000 } Total
The function that does this has some basic rules
For each digit pair to be summed we have the following rule table
A B Carry Total
0 0 0 0
1 0 0 1
0 1 0 1
1 1 1 0
Then we get onto the problem of multiplication
1101 * 10
Is just multiple additions!
So our multiply function could look like :
function multiply(x,y){
let total = 0;
for (i=0;i<y;i++){
total=add(total,add(x,x));
}
return total;
}
The complexity of the multiple addition operations is encapsulated by the closures of the multiply function.
This is now in and of itself an abstraction
*/
/*So our generator functions sit and wait until we call the next method on the returned iterator*/
/*This is a pull*/
/*How about a push mechanism?*/
/*<Observables enter stage left>.....*/
/*First we need a source of emitting (read pushing) data*/
/*
class Beacon {
constructor() {
let i = 0;
this._id = setInterval(() => this.emit(i++), 200);
}
emit(n) {
const limit = 10;
if (this.ondata) {
this.ondata("Ping");
}
if (n === limit) {
if (this.oncomplete) {
this.oncomplete();
}
this.destroy();
}
}
destroy() {
clearInterval(this._id);
}
}
//Kind of forget about this for now and focus on the next bit
function Observable(subscriber) {
let beacon = new Beacon();
beacon.ondata = (e) => subscriber.next(e);
beacon.onerror = (err) => subscriber.error(err);
beacon.oncomplete = () => subscriber.complete();
return () => {
beacon.destroy();
};
}
//This is the observable. It's a relatively simple contract that you subscribe to and then wait on the next, error and complete hooks
const unsubscribe = Observable({
next(ping) { console.log(ping); },
error(err) { console.error(err); },
complete() { console.log('done')}
});
*/
/*
Is it like stream?
Is it like a Promise?
Is it multicast or unicast?
Tune in next week? ;-)
*/
/*A quick encore before I go */
/*
A Promise and an Observable are both async primitives
A Promise is always multicast
A Promise always resolves or rejects asynchronously
A Promise cannot be cancelled
The subscribe method of an Observable is similar to the "then" of a Promise
An Observable is 'usually' asynchronous
An Observable is 'usually' unicast
*/
/*Back to first principles for a second*/
/*The inversion of control pattern (don't even think about mentioning Dependency Injection!!!)*/
/*
class puppet{
move_left_leg(){
console.log("Moving left leg");
}
move_right_leg(){
console.log("Moving right leg");
}
}
class puppeteer{
constructor(puppet){
this.puppet = puppet;
}
dance(){
this.puppet.move_left_leg();
this.puppet.move_right_leg();
this.puppet.move_right_leg();
this.puppet.move_left_leg();
}
}
let ppr = new puppeteer(new puppet);
ppr.dance();
*/
//The important point here is that the puppeteer controls the flow, not the puppet. The control is "handed over" to the puppeteer.
//We say the control flow has been inverted. Hence "Inversion of Control" or IoC.
//Now you can subsitute a different type of puppet in your line that instantiates the puppeteer, and that is called Dependency Injection,
//which IS depencency injection
//Real world example of IoC
/*
class TextBox{
constructor(visible, mandatory, readonly){
this.visible = visible;
this.mandatory = mandatory;
this.readonly = readonly;
}
render(){
console.log(`<input type='text' class='${this.visible ? 'show': 'hide'}' disabled='${this.readonly}' required='${this.mandatory}' />`);
}
}
class CheckBox{
constructor(visible, mandatory, readonly){
this.visible = visible;
this.mandatory = mandatory;
this.readonly = readonly;
}
render(){
console.log(`<input type='check' class='${this.visible ? 'show': 'hide'}' disabled='${this.readonly}' required='${this.mandatory}' />`);
}
}
class Form{
static render(field){
field.render();
}
}
Form.render(new TextBox(true,true,true));
Form.render(new CheckBox(true,true,true));
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment