Created
January 6, 2016 08:22
-
-
Save BobDickinson/4f55c98257adacdbce79 to your computer and use it in GitHub Desktop.
Test using CO to replace wait.for
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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