Skip to content

Instantly share code, notes, and snippets.

@BobDickinson
Created January 6, 2016 08:22
Show Gist options
  • Save BobDickinson/4f55c98257adacdbce79 to your computer and use it in GitHub Desktop.
Save BobDickinson/4f55c98257adacdbce79 to your computer and use it in GitHub Desktop.
Test using CO to replace wait.for
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
app.use(app.router);
var co = require('co');
var lodash = require('lodash');
// This is a standard JS async function (the last param is a completion callback that is called with err, result)
//
function nap(time, callback)
{
console.log("Napping for %s ms", time);
setTimeout(function()
{
if (time === 0)
{
callback(new Error("Time was zero"));
}
else
{
callback(null, time); // return amount of time waited
}
}, time);
}
// Example of a generator function (to show that you can yield a generator function - may get deprecated because Promises)
//
function * takeTwoNaps()
{
yield waitFor(nap, 100);
yield waitFor(nap, 200);
}
// Example of a generator with no yield (to show that you can yield to such a generator)
//
function * takeNoNaps()
{
console.log("Not taking any naps");
}
// Example of an async function wrapped in a promise to show that we can yield a Promise (because Promises)
//
function promiseToTakeNap(time)
{
return new Promise(function(resolve, reject)
{
console.log("Napping for %s ms", time);
setTimeout(function()
{
resolve(time); // return amount of time waited
}, time);
});
}
// Our waitFor wrapper which returns a "thunk" (to show that you can yield a thunk - may get deprecated because Promises)
//
function waitFor(asyncFn)
{
// Remove the asyncFn from the args (since we're going to pass the rest of them to asyncFn when we call it)
//
var args = lodash.rest(arguments);
return function(done)
{
args.push(done); // add the callback to the args
asyncFn.apply(this, args);
}
}
// A version of waitFor that uses a Promise wrapper around a Node async function (because Promises)
//
// This is functionally identically to the non-Promise waitFor above (it takes a Node async fn and params, supplies it's own
// completion callback, which when called, fullfils the Promise and satisfies the yield used to call waitForPromise). The
// only difference is that it uses a Promise wrapper instead of a thunk, which is more polically correct and maybe an easier
// transition to async/await, which awaits Promises.
//
function waitForUsingPromise(asyncFn)
{
// Remove the asyncFn from the args (since we're going to pass the rest of them to asyncFn when we call it)
//
var args = lodash.rest(arguments);
return new Promise(function(resolve, reject)
{
// Add a callback to the supplied params (the Node async function expects it)
//
args.push(function(err, result)
{
// When the async function calls the callback, that's when we fullfil the Promise
//
if (err)
{
reject(err);
}
else
{
resolve(result);
}
});
asyncFn.apply(this, args);
});
}
// This is our main function that is doing async processing (what would have been run in a fiber)
//
function * processRequest(req, res)
{
// Shows result from async function being returned
//
console.log("Before nap");
var naptime = yield waitFor(nap, 50);
console.log("After napping for: %j", naptime);
// Shows error from async function being thrown/caught
//
try
{
yield waitFor(nap, 0);
}
catch (err)
{
console.log("Nap Error (expected):", err);
}
// Shows we can yield to a generator that doesn't yield
//
yield takeNoNaps();
console.log("Done taking no naps");
// Shows we can yield to a generator that does itself yield
//
yield takeTwoNaps();
console.log("Done taking two naps");
// Shows we can yield a Promise wrapped around an async function
//
console.log("promiseToTakeNap: ", yield promiseToTakeNap(69));
// Shows we can yield a Promise wrapped around a passed-in async function and params
//
console.log("waitForPromise: ", yield waitForUsingPromise(nap, 75));
res.send("Hello");
console.log("Response sent");
}
app.get('/', function(req,res)
{
console.log("Launching request processor");
co(processRequest, req, res);
// The function above will exit before it's done running itself. Seeing the log line below is our indication that Node went
// on his way, and the subsequent logging of stuff happing in processRequest shows that we're asynchronously processing the
// request without blocking Node.
console.log("Done launching request processor");
});
var server = http.createServer(app);
server.listen(5000, function()
{
console.log('App listening on port ' + this.address().port + ", node version: " + process.version);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment