Skip to content

Instantly share code, notes, and snippets.

@dezull
Created January 29, 2017 05:24
Show Gist options
  • Save dezull/d8ad789f5025e53eee185f0f34e0ca0b to your computer and use it in GitHub Desktop.
Save dezull/d8ad789f5025e53eee185f0f34e0ca0b to your computer and use it in GitHub Desktop.
'use strict';
let http = require('http');
// Generator function, wrapper for http.get.
function *get(url) {
// Each generator function should call yield initially,
// to get the caller object, which contains done(result)
// and fail(error) functions. Pass the argument when
// done/failed doing asynchronous stuff appropriately.
const caller = yield;
http.get(url, (res) => {
let rawData = '';
res.on('data', (chunk) => rawData += chunk);
res.on('end', () => {
try {
caller.done(JSON.parse(rawData));
} catch (e) {
caller.fail(e);
}
});
});
}
// Generator function, just setTimeout
function *timeout(ms) {
// See *get for the first yield statement
const caller = yield;
setTimeout(() => {
caller.done('after ' + ms);
}, ms);
}
// This is our generator functions runner.
//
// Pass a generator function here, so you could use
// yield statements to pass a bunch of generator functions,
// and they will run one after another.
function run(genFn) {
let gen = genFn();
// Where we store the current generator object yielded in the runner block
let yielded;
// The caller object, each generator should call either done or fail
// once done with asynchronous work.
let result = {
done: (data) => {
// console.log('done', data);
yielded = gen.next(data);
resume();
},
fail: (error) => {
// console.error('error', error);
yielded = gen.throw(error);
resume();
},
};
// Resume to the next generator object in the runner block
function resume() {
if (yielded.done) return;
// yielded.value is the current generator object
let genFromYield = yielded.value;
// This will start the generator
let r = genFromYield.next();
if (!r.done) {
// This will stop at the `const caller = yield;` of the generator
r = genFromYield.next(result);
}
}
// Now, start with the first generator
yielded = gen.next();
resume();
}
console.log('start');
// So here is our runner for generators.
// We just need to 'yield' generator functions (not object) here,
// Each will run one after another, like synchronously
let runnerDone = false;
run(function* () {
console.log('runner start');
let ms1 = yield timeout(600);
console.log('>> timeout', ms1);
// try passing an invalid URL here, see how it will stop the runner
// when an error is thrown
try {
let json = yield get('http://nodejs.org/dist/index.json');
console.log('>> get %s ...', JSON.stringify(json).replace(/\s*/g, '').substr(0, 100));
} catch (e) {
console.error('>> get', e);
}
let ms2 = yield timeout(500);
console.log('>> timeout', ms2);
console.log('runner end');
runnerDone = true;
});
// Just for showing, outside the runner, the event loop still runs normally
let timer = setInterval(() => {
console.log('look ma, no blocking!');
if (runnerDone) clearInterval(timer);
}, 200);
console.log('end');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment