On Github yamalight / presentation-asyncjs
// Your typical synchronous code var getQueryResult = function (query) { var result = execQuery(userId); return result; } var result = getQueryResult('SELECT ?s WHERE { ?s ?p ?o }'); contaner.render(result);
// Both execQuery & getQueryResult are async var getQueryResult = function (query, cb) { execQuery(query, function(res) { res = res.toArray(); cb(res); }); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function(res) { container.render(res); });
var getQueryResult = function (query, cb) { execQuery(query, function(res) { expandResults(res, function(expandedRes) { filterResults(res, function(finalRes){ finalRes = finalRes.toArray(); cb(finalRes); }); }); }); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function(res) { container.render(res); });
The Pyramid of Doom
var processFinal = function (cb, finalRes){ cb(res); } var processExpandedResult = function (cb, expandedRes) { filterResults(res, processFinal.bind(this, cb)); } var processQueryResult = function (cb, res) { expandResults(res, processExpandedResult.bind(this, cb)); } var getQueryResult = function (query, cb) { execQuery(query, processQueryResult.bind(this, cb)); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function(res) { container.render(res); });
Still messy
var getQueryResult = function (query) { var result = execQuery(userId); return result; } var result = getQueryResult('SELECT ?s WHERE { ?s ?p ?o }'); if(result.error) { return container.error(result.error); } container.render(result.data);
// Both execQuery & getQueryResult are async var getQueryResult = function (query, cb) { execQuery(query, function(err, res) { if(err) { return cb(err); } res = res.toArray(); cb(null, res); }); }; getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function(err, res){ if(err) { return container.error(err); } container.render(res); });
Easy to learn but do not scale very well (get complex very quick)
See full spec for Promises/A+ on github.
var queryPromise = getQueryResult('SELECT ?s WHERE { ?s ?p ?o }'); // Some time later promisedPic.then(function(res) { container.render(res); });
It doesn't matter if it has been fulfilled yet or not
getQueryResult('SELECT ?s WHERE { ?s ?p ?o }') .then(function(res) { return filterResults(res) .then(function(filteredRes) { container.render(filteredRes); }); });
getQueryResult('SELECT ?s WHERE { ?s ?p ?o }') .then(function(res) { return filterResults(res); }) .then(function(res) { container.render(res); });
getQueryResult('SELECT ?s WHERE { ?s ?p ?o }') .then(function(res) { return filterResults(res); }) .then(function(res) { container.render(res); }, function(err) { contaner.error(err); });
getQueryResult('SELECT ?s WHERE { ?s ?p ?o }') .then(function(res) { return filterResults(res); }) .then(function(res) { container.render(res); }) .catch(function(err) { container.error(err); });
Fully featured promise library with focus on innovative features and performance
var readFile = Promise.promisify(require("fs").readFile); readFile("myfile.js", "utf8") .then(function(contents){ return eval(contents); }).then(function(result){ console.log("The result of evaluating myfile.js", result); }).catch(function(e){ console.log("Error reading file", e); });
var fs = Promise.promisifyAll(require("fs")); fs .readFileAsync("myfile.js", "utf8") .then(function(contents){ console.log(contents); }).catch(function(e){ console.error(e.stack); });
function getDataFor(input, callback) { return dataFromDataBase(input).nodeify(callback); }
task.js (Mozilla)
spawn(function*() { var data = yield $.ajax(url); $('#result').html(data); var status = $('#status').html('Download complete.'); yield status.fadeIn().promise(); yield sleep(2000); status.fadeOut(); });
function delay(ms) { return new Promise(function(f){ setTimeout(f, ms); }); } function PingPong() {} PingPong.prototype.ping = Promise.coroutine(function* (val) { console.log("Ping?", val) yield delay(500) this.pong(val+1) }); PingPong.prototype.pong = Promise.coroutine(function* (val) { console.log("Pong!", val) yield delay(500); this.ping(val+1) }); var a = new PingPong(); a.ping(0);
Built using node-fibers and Promises.
var getQueryResult = function (query, cb) { execQuery(query, function(res) { expandResults(res, function(expandedRes) { filterResults(res, function(finalRes){ cb(res); }); }); }); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function(res) { container.render(res); });
var getQueryResult = async(function(query) { var res = await(execQuery(query)); var expandedRes = await(expandResults(res)); var finalRes = await(filterResults(res)); return finalRes; }); getQueryResult('SELECT ?s WHERE { ?s ?p ?o }').then(function(res) { container.render(res); });
var getQueryResult = function (query) { var res = execQuery(query); finalRes = processResults(res); container.render(finalRes); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }');
var getQueryResult = compose([ execQuery, processResults, container.render.bind(container) ]); getQueryResult('SELECT ?s WHERE { ?s ?p ?o }');
var getQueryResult = function (query, cb) { container.showProgressIndicator(); execQuery(query, function(res) { processResults(res, function(finalRes) { container.render(finalRes); cb(); }); }); } getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function() { container.hideProgressIndicator(); });
var getQueryResult = composeAsync([ perform(container.showProgressIndicator.bind(container)), execQuery, processResults, perform(container.render.bind(container)) ]); getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', container.hideProgressIndicator.bind(container));
var getQueryResult = compose([ execQuery, processResults, container.render.bind(container) ]);
Same structure as sync
No need to change paradigm
// If you like jQuery or promises chains var getQueryResult = perform(container.showProgressIndicator.bind(container)) .map(execQuery) .map(processResults) .perform(container.render.bind(container)); getQueryResult .perform(container.hideProgressIndicator.bind(container)) ('SELECT ?s WHERE { ?s ?p ?o }');
// Reversed order var getQueryResult = async.compose( execQuery, processResults, // perform not in Async perform(container.showProgressIndicator.bind(container)) ); getQueryResult('SELECT ?s WHERE { ?s ?p ?o }', function (err, pic) { // Node convention if(err) { return container.showError(err); } container.render(pic); });
// Streams are EventEmitters dataStream.on('data', function(data) { // Consume data chunk }); dataStream.on('error', function(err) { // Handle errors }); dataStream.on('end', function() { // No more data, stream ended }); // With a pipe method dataStream.pipe(compressor('zip')).pipe(res);
Want to know more? Stream Handbook
Event-stream project
var es = require('event-stream'); var domstream = require('domnode-dom'); var queryStream = es.pipeline( domstream.createReadStream('input.query', 'keyup'), es.mapSync(trim), es.mapSync(toLowerCase), es.mapSync(function(text) { container.showProgressIndicator(); return text; }), es.map(getQueryResult), ); queryStream.on('data', container.render.bind(container)); queryStream.on('error', container.error.bind(container)); queryStream.on('end', container.hideProgressIndicator.bind(container));
var queryText = $('input[type="text"][name="query"]') .asEventStream('keyup') .map(".target.value") .map(trimText) .toProperty(""); // memory ! queryText .sample(500) .skipDuplicates() .filter(shorterThan(3)) .map(getQueryResult) .onValue(function (res) { queryText.on('data', container.appendResult.bind(container)); queryText.on('end', container.end.bind(container)); });
Use the most simple tool that can solve your problem.