Created
November 12, 2015 16:34
-
-
Save stevereich/46a869a267fcb9a03d2d to your computer and use it in GitHub Desktop.
This is an example of using closures and callback functions with Coldfusion or Railo. This will probably bend your mind a little bit!
This file contains 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
component output='false' { | |
// init component | |
public callback_component function init(){ | |
return this; | |
}; | |
// this function implicitly takes 2 named arguments. In this case, the arguments scope | |
// can be treated as an object with name value pairs or an array with the index being | |
// equal to the position they are expected. This was probably part of the thinking when | |
// Jeremy and JJ Allaire decided not to use a zero index way back when... | |
// | |
// arguments['fullname'] == arguments.fullname == arguments[1] | |
// | |
// (side note: though a similar circumstance, this is not the same case in javascript) | |
// | |
public string function getFirstName(required string fullName, callback){ | |
try{ | |
// we'll set our return variable and parse out the first name | |
var firstname = listgetat(arguments.fullName, 1, ' '); | |
// pass return variable to our callback function | |
// this is going to run with out return | |
callback(firstname); | |
} | |
catch(any e){ | |
// if error, we will set the return variable to the error message | |
firstname = e.detail; | |
} | |
finally{ | |
// Finally ALWAYS runs... like a promise! | |
return firstname; | |
} | |
}; | |
// this is the same function as above, but with only one argument defined in the | |
// function definition. We can still pass a callback to it though... as long as | |
// the function know it could be a possibility. | |
public string function anotherWayToAcceptCallbackAndGetFirstName(required string fullName){ | |
// we'll set our return variable and parse out the first name | |
var firstname = listgetat(arguments.fullName, 1, ' '); | |
// wait? what's this? it's a closure. this function has access to all the variables of it's | |
// parent function. However, the parent function does not have access any variables this | |
// closure function sets. | |
var throwItAroundOneMoreTime = function(thing){ | |
// this return is only available to the parent function, which is then free to | |
// return it to 2 friends, and so on, and so on, and so on... :) | |
return reverse(thing); | |
}; | |
// this is our calback! I romise that no illicit drugs were consumed in the assembly of | |
// this string. let's break it down.... | |
// | |
// arguments is an object or an array. without a named index, we have to treat it as array | |
// arguments index is arraylen(arguments). this is assumming that no matter how many arguments | |
// were passed to this function, the callback was passed last. so we have: | |
// | |
// arguments[arraylen(arguments)] <<<<---- this is our function. if we just passed it the | |
// return of the called function, it would be arguments[arraylen(arguments)](firstname). | |
// | |
// but for the mere shock value, let's reverse the return, pass it to our closure, | |
// reverse it back, and the return it for our call back to return... haha! | |
// | |
// throwItAroundOneMoreTime(reverse(firstname)) <<<--- this is our argument we pass to our callback | |
// | |
// | |
// | |
// we run our callback function, not return it. | |
var callback = arguments[arraylen(arguments)]; | |
callback(throwItAroundOneMoreTime(reverse(firstname))); | |
// we only return our return! | |
return firstname; | |
}; | |
} |
This file contains 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
<html> | |
<head> | |
<title>Callbacks and Closures and Coldfusion... oh my!</title> | |
<style> | |
*{box-sizing:border-box} | |
html,body{background:#F5F5F5;width:100%;height:100%;margin:0;padding:0;font-family:sans-serif;overflow:hidden} | |
div#head{position:fixed;top:0;left:0;right:0;height:60px;line-height:60px;box-shadow:0 5px 20px 0 rgba(0,0,0,.2); | |
text-align:center;font-size:2em;font-weight:bold;color:#F5F5F5;background:#666;border-bottom:1px #333 solid} | |
ul{position:absolute;width:550px;left:50%;margin-left:-275px;top:30%;} | |
ul>li{font-size:1.2em;padding-left:0} | |
div#foot{position:fixed;bottom:0;left:0;right:0;text-align:center;height:40px} | |
a,a:link,a:visited,a:hover,a:acitve{text-decoration:none;font-size:.5em;color:#666} | |
</style> | |
</head> | |
<body> | |
<cfscript> | |
request.layout = false; | |
// just for the sake of showing how deep the rabbit hole is that Mike Arnold pulled me into, | |
// we'll wrap this up with a single function with nested closures... | |
// variables scope our component so it doesn't get reinit() each time the function is called | |
variables.comp = createobject('component','callback_component').init(); | |
public string function wtf(){ | |
// local scope the return variable | |
var theReturn = ''; | |
// we'll switch on a single argument. in production we would want to do string validation | |
switch(arguments[1]){ | |
// ok.. now the fun part. if 'steve' is passed as the arg | |
case 'steve': | |
// call our function. we pass fullname as argument[1] and a function as argument[2]. | |
// the argument that I have in the callback function can be anything. When the function | |
// runs, it will assign it's return to that argument and run it through our callback, | |
// which in turn, we will assign it to this functions return var... stay with me!! :) | |
variables.comp.getFirstName('Jimmie Chapman',function(StevesArg){ | |
theReturn = """" & repeatstring(StevesArg & '!',5) & """"; | |
}); | |
break; | |
// if 'mike' is passed as the arg | |
case 'mike': | |
// same as steve here... | |
variables.comp.getFirstName('Jimmie Chapman',function(mikesArg){ | |
theReturn = reverse(mikesArg).toLowercase() & "."; | |
}); | |
break; | |
// if 'jay' is passed as the arg | |
case 'jay': | |
// jay is special and he is going to call the second function in our component. if you | |
// remember, that function had a closure function that it tossed the return back and forth. | |
// well guess what? as payback, his callback function has a closure function too. Is your | |
// brain turned completely inside out yet? Mine is.. but we're almost there. | |
variables.comp.anotherWayToAcceptCallbackAndGetFirstName('Jimmie Chapman',function(jsyArg){ | |
// this is a closure within the callback | |
var whosHouse = function(arg){ | |
return arg & " Chapman loves OU football."; | |
}; | |
// this is oru return var and we are setting the value to the return of our closure | |
// function, passing it the return of the callback's parent function. | |
theReturn = whosHouse(jsyArg); | |
}); | |
break; | |
} | |
// in our swith, we were only assigning values to our return variable. | |
// we return it here.... | |
return theReturn; | |
} | |
// now... we will set variables and test this mutha.... | |
local.steve = wtf('steve'); | |
local.mike = wtf('mike'); | |
local.jay = wtf('jay'); | |
/* ==================================================== */ | |
// this is the output using the three variables above... | |
writeoutput("<div id='head'>Closure. Callbacks. Coldfusion. Oh my...</div>"); | |
writeoutput("<ul>"); | |
writeoutput("<li>Steve yelled, " & local.steve & "</li>"); | |
writeoutput("<li>Mike thinks it's cool to say his name backwards... """ & local.mike & """</li>"); | |
writeoutput("<li>Jay got closure in that " & local.jay & "</li>"); | |
writeoutput("</ul>"); | |
writeoutput("<div id='foot'>Steve Reich, Professional Application Developer<br>"); | |
writeoutput("<a href='mailto:[email protected]'>email me with any questions</a></div>"); | |
</cfscript> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment