Skip to content

Instantly share code, notes, and snippets.

@damirka
Created April 25, 2017 10:44
Show Gist options
  • Save damirka/ec46329157878fd5c688af8aa23a6225 to your computer and use it in GitHub Desktop.
Save damirka/ec46329157878fd5c688af8aa23a6225 to your computer and use it in GitHub Desktop.
Using generators to execute async code in a sync manner
'use strict';
const EventEmitter = require('events');
/**
* Runs generator and puts EventEmitter context in it to let user
* emit any events inside generator and subscribe to them from outside.
*
* @param {Function} gen Function which returns generator
* @return {EventEmitter} Returns emitter instance which is bound
*/
function runGenerator(gen) {
let res;
let emitter = new EventEmitter();
let iterator = gen.call(emitter);
(function iterate(value) {
res = iterator.next(value);
if (!res.done) {
return (res.value instanceof Promise)
? res.value.then((value) => iterate(value))
: setImmediate(() => iterate(res.value));
}
})();
return emitter;
}
// EXAMPLE
const Pool = require('pg').Pool;
const Cursor = require('pg-cursor');
const pool = new Pool();
let it = runGenerator(function* () {
let chunk = 2;
let sql = 'SELECT * FROM generate_series(0, 9, 1)';
let client = yield pool.connect();
let cursor = yield client.query(new Cursor(sql));
let data;
this.emit('init');
while (data !== null) {
data = yield new Promise((resolve) => {
cursor.read(chunk, (err, rows) => resolve(rows.length ? rows : null));
});
if (data !== null) {
this.emit('data', data);
}
}
yield client.release();
this.emit('end');
});
it.on('init', () => console.log('connection established'));
it.on('data', (data) => {
// ... do anything with data ...
});
it.on('end', () => console.log('client released'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment