Skip to content

Instantly share code, notes, and snippets.

@ifraixedes
Last active November 24, 2016 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ifraixedes/62a7155b87e7e7d0c71d to your computer and use it in GitHub Desktop.
Save ifraixedes/62a7155b87e7e7d0c71d to your computer and use it in GitHub Desktop.
Generators & Async function - Source files used for talks (meetups, etc)
{
"env": {
"development": {
"presets":["es2015-node5"],
"plugins": ["transform-async-to-generator"]
}
}
}
node_modules
'use strict';
import debug from 'debug';
import {promisedNaturalAdd} from './helpers';
let d = debug('async-funcs');
// NOTE: functions passed to `then` are named to make more clearer for the audience
// Basic async function
async function basicAsync(num1, num2) {
let d = debug('async-funcs:basicAsync');
d('START');
let res = await promisedNaturalAdd(num1, num2);
d('END');
return res;
}
// This is WRONG
// This get a promise which resolve or reject when async function ends
// It does NOT get the result revolved by the promise or the reject error in synchronous way by try / catch
try {
let res = basicAsync(10, 5)
d('This get a promise object: %s', res);
} catch (e) {
console.error(e);
}
// This is RIGTH
basicAsync(10, 5).then(
function reolved(result) {
d('This get the result of the operations made by the async function: %s', result);
},
function rejected(err) {
console.error(err);
}
);
// This is RIGTH
basicAsync(10, -5).then(
function reolved(result) {
d('This get the result of the operations made by the async function: %s', result);
},
function rejected(err) {
d('We expected to get this error: "%s"', err);
}
);
// Don't forget to register global events for unhandled rejecte promises
basicAsync(10, 5).then(
function reolved(result) {
// This doesn't parse due the `res` is not defined
d(res); // the name of the argument is `result` NOT `res`
},
function rejected(err) {
console.error(err);
}
);
// without this we have missed the syntax error
process.on('unhandledRejection', (err, promise) => {
d('Gathered unhandled rejection: %s', err);
});
// The body of async function operate synchronously with promise
// resolve/reject when `await` statement is used so try/catch just work
// inside of them
async function basicAsyncTryCatch(num1, num2) {
let res;
try {
d('Basic Async (try-catch): START');
res = await promisedNaturalAdd(num1, num2);
} catch (e) {
d('Basic Async (try-catch): ERROR: %s', e);
}
d('Basic Async (try-catch): END');
return res;
}
basicAsyncTryCatch(10, -5).then(
function resolve(res) {
d('promise will resolve with undefined: %s', res)
},
function reject(e) {
d('promise should always resolved so this message should not appear: %s', e);
}
);
'use strict';
import debug from 'debug';
import { join, extname } from 'path';
import { readdir, stat } from 'fs';
import { cbToPromise } from './helpers';
let d = debug('listJSFiles');
async function printFilesList(path) {
d('listing files');
let filesNames = await cbToPromise(readdir, path);
let stats = await Promise.all(filesNames.map(f => cbToPromise(stat, join(path, f))));
stats.forEach((st, idx) => {
if (st.isFile() && (extname(filesNames[idx]) === '.js')) {
d('file: %s', filesNames[idx]);
}
});
}
printFilesList(__dirname);
process.on('unhandledRejection', (err, promise) => {
console.error('unhandledRejection: %s', err);
});
'use strict';
let d = require('debug')('gen2async');
let promisedNaturalAdd = require('./helpers').promisedNaturalAdd;
function asyncify(generator) {
function iterate(g, resolvedValue) {
let i = g.next(resolvedValue);
if (i.done) {
return i.value;
}
return i.value.then(res => {
return iterate(g, res);
}, err => {
g.throw(err);
return iterate(g);
});
}
return function (args) {
let g = generator.apply(generator, args);
return iterate(g);
}
}
function* gen() {
d('START: gen');
let res;
try {
res = yield promisedNaturalAdd(10, 5);
d('First result value (10, 5): %s', res);
res = yield promisedNaturalAdd(10, -5);
d('Second result value (10, -5): %s', res);
} catch (e) {
d('Error gathered in catch: %s', e);
}
d('END: gen');
}
let afn = asyncify(gen);
afn().then(
function () {
d('END');
}).catch(
function (e) {
d('END with error: %s', e);
});
process.on('unhandledRejection', (err, promise) => {
console.error('unhandledRejection: %s', err);
});
'use strict';
let d = require('debug')('generators');
function* simpleGen(initAmount) {
yield initAmount;
yield initAmount * 10;
yield initAmount * 100;
}
let sg = simpleGen(5);
d('Getting value from generator calling next');
while (true) {
let i = sg.next();
d(i);
if (i.done) {
break;
}
}
d('Iterating a generator as an Iterator');
sg = simpleGen(5);
for (let i of sg) {
d(i);
}
// LAZY GENERATOR: infinite sequence
function* exponential() {
let value = 0;
while (true) {
yield value * value;
value++;
}
}
let ex = exponential();
d('Get the 10 first exponential values');
for (let x = 0; x < 10; x++) {
let y = ex.next().value;
d('x: %s | y: %s', x, y);
}
d('Get the next 5');
for (let x = 10; x < 15; x++) {
let y = ex.next().value;
d('x: %s | y: %s', x, y);
}
// GENERATOR SUBROGATION
d('Generator delegates execution to another generator');
function* weirdGrowth() {
let x = 0;
for (let i = 0; i < 10; i++) {
yield* keepConstant(Math.random() * i * 10, i);
}
}
function* keepConstant(times, value) {
for (let i = 0; i < times; i++) {
yield value;
}
}
let wg = weirdGrowth();
let lastValue = wg.next().value;
let counter = 1;
for (let i of wg) {
if (lastValue !== i) {
d('%s value has returned %s times', lastValue, counter);
lastValue = i;
counter = 1;
} else {
counter++;
}
}
d('%s value has returned %s times', lastValue, counter);
'use strict';
let debug = require('debug');
module.exports = {
promisedNaturalAdd: promisedNaturalAdd,
cbToPromise: cbToPromise
};
// NOTE: functions passed to `then` are named with the aim to make it
// clearer for some part audience
// Remember what a promise is, returning one from a custom function
function promisedNaturalAdd(num1, num2) {
let d = debug('helpers:promisedNaturalAdd');
d('Delayed Natural Add: START');
let p = new Promise(function (resolve, reject) {
// This executes synchronous
d('Executing promise callback');
if ((num1 < 0) || (num2 < 0)) {
reject(new Error('arguments must be natural numbers'));
return;
}
resolve(num1 + num2);
}).then(
// This two functions are called asynchronous.
// It does NOT matter if the functions passed to
// the Promise constructor are called synchronously or asynchronously
function resolve(res) {
d('This only forward the result');
return res;
},
function reject(err) {
d('This only forward the error');
throw err;
}
);
d('Delayed Natural Add: END');
return p;
}
function cbToPromise(fn) {
let params = Array.prototype.slice.call(arguments, 1);
return new Promise((resolve, reject) => {
params.push(function (err) {
if (err) {
reject(err);
return;
}
switch (arguments.length) {
case 1:
resolve();
break;
case 2:
resolve(arguments[1]);
break;
default:
resolve(Array.prototype.slice.call(arguments, 1));
}
});
fn.apply(null, params);
});
}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004
(http://www.wtfpl.net/about/)
Copyright (C) 2016 Ivan Fraixedes (https://ivan.fraixed.es)
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "generators-and-async-funcs-talk",
"version": "0.0.0",
"description": "",
"scripts": {
"generators": "DEBUG=generators node generators.js",
"async": "DEBUG='async-funcs,helpers*' babel-node async-funcs.js",
"gen2async": "DEBUG='gen2async,helpers*' node gen-to-async.js",
"listFiles": "DEBUG='listJSFiles,helpers*' babel-node example-list-js-files.js"
},
"author": "Ivan Fraixedes <ivan@fraixed.es> (http://ivan.fraixed.es)",
"license": "WTFPL",
"devDependencies": {
"babel-cli": "^6.4.0",
"babel-plugin-transform-async-to-generator": "^6.4.0",
"babel-preset-es2015-node5": "^1.1.1"
},
"dependencies": {
"debug": "^2.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment