I am basically quite sure this pattern must exist and possess a name... for now I will call it "gate pattern"...
Here it is:
In my webpage's javascript, I have to trigger various asynchronous processes. Let's not discuss how trully async js is, but anyway I have to trigger 2 or 3 AJAX calls, must be sure, the UI build-up has finished, and so on.
Only then, when all these processes have finished, I want to do run a certain function. And precisely once.
Example
1: cropStore loaded()
2: resizeEvent()
3: productStore loaded()
The Pattern:
At the end of every (sucessful) Ajax-load-callback, the end of the GUI construction routine, etc... I set a respective flag from false to true and call gatedAction()
onEvent( 'load',
{
.... // whatever has to happen in response to cropStored, resized, etc...
// lastly:
f1 = true; //resp f2, f3, ...
gatedAction();
}
Gate will check the flags, return if any flag is still unset, only calling the target function, if all flags (or as I call them: gates) are open. If all my async pre-conditions call gatedAction() exactly once, I hope I can be sure, the actual targetFunction is called exactly once().
gatedAction ()
{
// Gate
if ( ! f1) return;
if ( ! f2) return;
if ( ! f3) return;
// actual Action ( <=> f1==f2==f3==true )
targetFunction();
}
In practice it works reliably. On a side-note: I think java-typical (not js-typical) synchronization/volatile concerns can be ignored, because javascript is not truly multithreading. Afaik a function is never stopped in the middle of it, just to grant another javascript function in the same document run-time...
So, anyone, is there a name for this? :-)
I need this pattern actually quite often, especially with complex backend UIs.. (and yes, I think, I will turn the above butt-ugly implementation into a more reusable javascript... With a gates array and a target function.)
It sounds like Balking pattern to me.
It is similar to the Rendezvous pattern, although that pattern is generally used in the context of multithreaded real-time systems.
I have no idea, if your pattern has a special name, but it seems equivalent to just using a counting semaphore, which blocks the thread, which started all those other actions, until they all made a V-invocation. Of course, there are no threads and semaphores in JavaScript, but instead of using many boolean variables you could use just one integer for counting.
In addition to the actual answer to your question, you might be interested in the Rx framework for Javascript. It's a port of the .NET version and allows you to compose events, so you don't have to work with tons of flag variables. It's meant for this sort of thing.
http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx
Related
Intro
This topic has been the bane of many questions and answers on StackOverflow -and in many other tech-forums; however, most of them are specific to exact conditions and even worse: "over-all" security in script-injection prevention via dev-tools-console, or dev-tools-elements or even address-bar is said to be "impossible" to protect. This question is to address these issues and serve as current and historical reference as technology improves -or new/better methods are discovered to address browser security issues -specifically related to script-injection attacks.
Concerns
There are many ways to either extract -or manipulate information "on the fly"; specifically, it's very easy to intercept information gathered from input -to be transmitted to the server - regardless of SSL/TLS.
intercept example
Have a look here
Regardless of how "crude" it is, one can easily use the principle to fabricate a template to just copy+paste into an eval() in the browser console to do all kinds of nasty things such as:
console.log() intercepted information in transit via XHR
manipulate POST-data, changing user-references such as UUIDs
feed the target-server alternative GET (& post) request information to either relay (or gain) info by inspecting the JS-code, cookies and headers
This kind of attack "seems" trivial to the untrained eye, but when highly dynamic interfaces are in concern, then this quickly becomes a nightmare -waiting to be exploited.
We all know "you can't trust the front-end" and the server should be responsible for security; however - what about the privacy/security of our beloved visitors? Many people create "some quick app" in JavaScript and either do not know (or care) about the back-end security.
Securing the front-end as well as the back-end would prove formidable against an average attacker, and also lighten the server-load (in many cases).
Efforts
Both Google and Facebook have implemented some ways of mitigating these issues, and they work; so it is NOT "impossible", however, they are very specific to their respective platforms and to implement requires the use of entire frameworks plus a lot of work -only to cover the basics.
Regardless of how "ugly" some of these protection mechanisms may appear; the goal is to help (mitigate/prevent) security issues to some degree, making it difficult for an attacker. As everybody knows by now: "you cannot keep a hacker out, you can only discourage their efforts".
Tools & Requirements
The goal is to have a simple set of tools (functions):
these MUST be in plain (vanilla) javascript
together they should NOT exceed a few lines of code (at most 200)
they have to be immutable, preventing "re-capture" by an attacker
these MUST NOT clash with any (popular) JS frameworks, such as React, Angular, etc
does NOT have to be "pretty", but readable at least, "one-liners" welcome
cross-browser compatible, at least to a good percentile
Runtime Reflection / Introspection
This is a way to address some of these concerns, and I don't claim it's "the best" way (at all), it's an attempt.
If one could intercept some "exploitable" functions and methods and see if "the call" (per call) was made from the server that spawned it, or not, then this could prove useful as then we can see if the call came "from thin air" (dev-tools).
If this approach is to be taken, then first we need a function that grabs the call-stack and discard that which is not FUBU (for us by us). If the result of this function is empty, hazaa! - we did not make the call and we can proceed accordingly.
a word or two
In order to make this as short & simple as possible, the following code examples follow DRYKIS principles, which are:
don't repeat yourself, keep it simple
"less code" welcomes the adept
"too much code & comments" scare away everybody
if you can read code - go ahead and make it pretty
With that said, pardon my "short-hand", explanation will follow
first we need some constants and our stack-getter
const MAIN = window;
const VOID = (function(){}()); // paranoid
const HOST = `https://${location.host}`; // if not `https` then ... ?
const stak = function(x,a, e,s,r,h,o)
{
a=(a||''); e=(new Error('.')); s=e.stack.split('\n'); s.shift(); r=[]; h=HOSTPURL; o=['_fake_']; s.forEach((i)=>
{
if(i.indexOf(h)<0){return}; let p,c,f,l,q; q=1; p=i.trim().split(h); c=p[0].split('#').join('').split('at ').join('').trim();
c=c.split(' ')[0];if(!c){c='anon'}; o.forEach((y)=>{if(((c.indexOf(y)==0)||(c.indexOf('.'+y)>0))&&(a.indexOf(y)<0)){q=0}}); if(!q){return};
p=p[1].split(' '); f=p[0]; if(f.indexOf(':')>0){p=f.split(':'); f=p[0]}else{p=p.pop().split(':')}; if(f=='/'){return};
l=p[1]; r[r.length]=([c,f,l]).join(' ');
});
if(!isNaN(x*1)){return r[x]}; return r;
};
After cringing, bare in mind this was written "on the fly" as "proof of concept", yet tested and it works. Edit as you whish.
stak() - short explanation
the only 2 relevant arguments are the 1st 2, the rest is because .. laziness (short answer)
both arguments are optional
if the 1st arg x is a number then e.g. stack(0) returns the 1st item in the log, or undefined
if the 2nd arg a is either a string -or an array then e.g. stack(undefined, "anonymous") allows "anonymous" even though it was "omitted" in o
the rest of the code just parses the stack quickly, this should work in both webkit & gecko -based browsers (chrome & firefox)
the result is an array of strings, each string is a log-entry separated by a single space as function file line
if the domain-name is not found in a log-entry (part of filename before parsing) then it won't be in the result
by default it ignores filename / (exactly) so if you test this code, putting in a separate .js file will yield better results than in index.html (typically) -or whichever web-root mechanism is used
don't worry about _fake_ for now, it's in the jack function below
now we need some tools
bore() - get/set/rip some value of an object by string reference
const bore = function(o,k,v)
{
if(((typeof k)!='string')||(k.trim().length<1)){return}; // invalid
if(v===VOID){return (new Function("a",`return a.${k}`))(o)}; // get
if(v===null){(new Function("a",`delete a.${k}`))(o); return true}; // rip
(new Function("a","z",`a.${k}=z`))(o,v); return true; // set
};
bake() - shorthand to harden existing object properties (or define new ones)
const bake = function(o,k,v)
{
if(!o||!o.hasOwnProperty){return}; if(v==VOID){v=o[k]};
let c={enumerable:false,configurable:false,writable:false,value:v};
let r=true; try{Object.defineProperty(o,k,c);}catch(e){r=false};
return r;
};
bake & bore - rundown
These are failry self-explanatory, so, some quick examples should suffice
using bore to get a property: console.log(bore(window,"XMLHttpRequest.prototype.open"))
using bore to set a property: bore(window,"XMLHttpRequest.prototype.open",function(){return "foo"})
using bore to rip (destroy carelessly): bore(window,"XMLHttpRequest.prototype.open",null)
using bake to harden an existing property: bake(XMLHttpRequest.prototype,'open')
using bake to define a new (hard) property: bake(XMLHttpRequest.prototype,'bark',function(){return "woof!"})
intercepting functions and constructions
Now we can use all the above to our advantage as we devise a simple yet effective interceptor, by no means "perfect", but it should suffice; explanation follows:
const jack = function(k,v)
{
if(((typeof k)!='string')||!k.trim()){return}; // invalid reference
if(!!v&&((typeof v)!='function')){return}; // invalid callback func
if(!v){return this[k]}; // return existing definition, or undefined
if(k in this){this[k].list[(this[k].list.length)]=v; return}; //add
let h,n; h=k.split('.'); n=h.pop(); h=h.join('.'); // name & holder
this[k]={func:bore(MAIN,k),list:[v]}; // define new callback object
bore(MAIN,k,null); let f={[`_fake_${k}`]:function()
{
let r,j,a,z,q; j='_fake_'; r=stak(0,j); r=(r||'').split(' ')[0];
if(!r.startsWith(j)&&(r.indexOf(`.${j}`)<0)){fail(`:(`);return};
r=jack((r.split(j).pop())); a=([].slice.call(arguments));
for(let p in r.list)
{
if(!r.list.hasOwnProperty(p)||q){continue}; let i,x;
i=r.list[p].toString(); x=(new Function("y",`return {[y]:${i}}[y];`))(j);
q=x.apply(r,a); if(q==VOID){return}; if(!Array.isArray(q)){q=[q]};
z=r.func.apply(this,q);
};
return z;
}}[`_fake_${k}`];
bake(f,'name',`_fake_${k}`); bake((h?bore(MAIN,h):MAIN),n,f);
try{bore(MAIN,k).prototype=Object.create(this[k].func.prototype)}
catch(e){};
}.bind({});
jack() - explanation
it takes 2 arguments, the first as string (used to bore), the second is used as interceptor (function)
the first few comments explain a bit .. the "add" line simply adds another interceptor to the same reference
jack deposes an existing function, stows it away, then use "interceptor-functions" to replay arguments
the interceptors can either return undefined or a value, if no value is returned from any, the original function is not called
the first value returned by an interceptor is used as argument(s) to call the original and return is result to the caller/invoker
that fail(":(") is intentional; an error will be thrown if you don't have that function - only if the jack() failed.
Examples
Let's prevent eval from being used in the console -or address-bar
jack("eval",function(a){if(stak(0)){return a}; alert("having fun?")});
extensibility
If you want a DRY-er way to interface with jack, the following is tested and works well:
const hijack = function(l,f)
{
if(Array.isArray(l)){l.forEach((i)=>{jack(i,f)});return};
};
Now you can intercept in bulk, like this:
hijack(['eval','XMLHttpRequest.prototype.open'],function()
{if(stak(0)){return ([].slice.call(arguments))}; alert("gotcha!")});
A clever attacker may then use the Elements (dev-tool) to modify an attribute of some element, giving it some onclick event, then our interceptor won't catch that; however, we can use a mutation-observer and with that spy on "attribute changes". Upon attribute-change (or new-node) we can check if changes were made FUBU (or not) with our stak() check:
const watchDog=(new MutationObserver(function(l)
{
if(!stak(0)){alert("you again! :D");return};
}));
watchDog.observe(document.documentElement,{childList:true,subtree:true,attributes:true});
Conclusion
These were but a few ways of dealing with a bad problem; though I hope someone finds this useful, and please feel free to edit this answer, or post more (or alternative/better) ways of improving front-end security.
Unlike other "FRP" libraries, Rx doesn't prevent glitches: callbacks invoked with time-mismatched data. Is there a good way to work around this?
As an example, imagine that we have a series of expensive computations derived from a single stream (e.g. instead of _.identity, below, we do a sort, or an ajax fetch). We do distinctUntilChanged to avoid recomputing the expensive things.
sub = new Rx.Subject();
a = sub.distinctUntilChanged().share();
b = a.select(_.identity).distinctUntilChanged().share();
c = b.select(_.identity).distinctUntilChanged();
d = Rx.Observable.combineLatest(a, b, c, function () { return _.toArray(arguments); });
d.subscribe(console.log.bind(console));
sub.onNext('a');
sub.onNext('b');
The second event will end up causing a number of glitchy states: we get three events out, instead of one, which wastes a bunch of cpu and requires us to explicitly work around the mismatched data.
This particular example can be worked around by dropping the distinctUntilChanged, and writing some wonky scan() functions to pass through the previous result if the input hasn't changed. Then you can zip the results, instead of using combineLatest. It's clumsy, but doable.
However if there is asynchrony anywhere, e.g. an ajax call, then zip doesn't work: the ajax call will complete either synchronously (if cached) or asynchronously, so you can't use zip.
Edit
Trying to clarify the desired behavior with a simpler example:
You have two streams, a and b. b depends on a. b is asynchronous, but the browser may cache it, so it can either update independently of a, or at the same time as a. So, a particular event in the browser can cause one of three things: a updates; b updates; both a and b update. The desired behavior is to have a callback (e.g. render method) invoked exactly once in all three cases.
zip does not work, because when a or b fires alone, we get no callback from zip. combineLatest does not work because when a and b fire together we get two callbacks.
The concept
both a and b update
where both a and b are observables, doesn't exist as a primitive in Rx.
There is no lossless, general operator that can be defined to decide when it receives a notification from a whether it should pass it downstream or hold off until it receives a notification from b. Notifications in Rx do not natively carry "both" semantics, or any semantics beyond the Rx Grammar for that matter.
Furthermore, Rx's serial contract prevents an operator from taking advantage of overlapping notifications in an attempt to achieve this goal. (Though I suspect that relying on race conditions isn't your desired approach anyway.)
See ยงยง4.2, 6.7 in the Rx Design Guidelines.
Thus, what I meant above by "There is no lossless, general operator that can be defined..." is that given two observables a and b with independent notifications, any operator that attempts to decide when it receives a notification from a or b whether it must push immediately or wait for the "other" value, must rely on arbitrary timings. It's guesswork. So this hypothetical operator must either drop values (e.g., DistinctUntilChanged or Throttle), or drop time (e.g., Zip or Buffer), though probably some combination of both.
Therefore, if the agent has the ability to push a alone, or b alone, or a and b together as a notification unit, then it's the developer's responsibility to reify this concept of notification unit themselves.
A 3-state type is required: a | b | {a,b}
(Please excuse my lousy JS)
var ab = function(a, b) { this.a = a; this.b = b; }
sub.onNext(new ab('a')); // process a alone
sub.onNext(new ab('a', 'b')); // process a and b together
sub.onNext(new ab(null, 'c')); // process c alone
The shape of the observable's query no longer matters. Observers must be defined to accept this data type. It's the generator's responsibility to apply any necessary buffering or timing calculations based on the semantics of its internal state in order to produce correct notifications for its observers.
By the way, thank you for providing a simple explanation in your edit (it seems clear to me anyway). I had first heard about "glitches" in this Rx forum discussion. As you can see, it was never really concluded. Now I wonder whether that OP's problem was really as simple as this, assuming that I've understood your problem correctly, of course. :-)
Update:
Here's another related discussion, including some more of my thoughts on why Rx is not FRP:
https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71-c97b-428e-ad71-324055a3cd03/another-discussion-on-glitches-and-rx?forum=rx
In my work, I frequently encounter following situation:
Situation A:
I need to make multiple ajax calls in one function to retrieve data from server. So I have to make callback functions and define a counter to determine whether all the calls get done.
For example , in each of the sub-functions ( with ajax calls), at the end of the done, I would callback to check the counter's value.
ajax.done(funciton(jsResponse){
.......
base.ajaxLoaded++;
base.dataLoaded();
});
then in base function, I check the value:
dataLoaded: function()
{
var _this = this;
if (_this.ajaxLoaded == 4)
{
// all loaded
_self.render();
_this.afterInit();
}
}
Situation B:
There is a modal pop up triggered by the completion of an animation. So, I have following choices:
1) make a setTimeout function with a timer ( estimated the length of animation)
something like:
setTimeout(function(){
window.MYAPP.triggerMymodal();
},1000);
2) set up a interval function to check repeatedly whether a flag's value has changed and I embedded this flag into the animation finish function, to set it true or false.
if this flag true then make my next move and kills this interval.
3) change animation div attributes and check it use interval function.
Situation C:
Use window.print() function to print something and then need detect when it's finish. This has been asked by myself in this:
how to detect window.print() finish
My Question:
In JavaScript, is there a certain kind of method or Technic to deal with those functions which have unknown execution time? or this is just a case by case thing based on what technology you use?
Yes, the modern approach to dealing with this is called Promises. Various libraries implement the concept, which is basically that you can chain together groups of things that need to happen, either is parallel or serial, and then define success and failure outcomes for each of them.
It takes a bit of time to get your head around it but once you do the code is much more straightforward.
I am have some JavaScript functions that run on both the client (browser) and the server (within a Java Rhino context). These are small functions - basically little validators that are well defined and don't rely upon globals or closures - self-contained and portable.
Here's an example:
function validPhoneFormat(fullObject, value, params, property) {
var phonePattern = /^\+?([0-9\- \(\)])*$/;
if (value && value.length && !phonePattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
To keep things DRY, my server code gets a handle on each of these functions and calls toString() on them, returning them to the browser as part of a JSON object. Something like this:
{ "name" : "phoneNumber",
"policies" : [
{ "policyFunction" : "\nfunction validPhoneFormat(fullObject, value, params, property) {\n var phonePattern = /^\\+?([0-9\\- \\(\\)])*$/;\n if (value && value.length && !phonePattern.test(value)) {\n return [{\"policyRequirement\":\"VALID_PHONE_FORMAT\"}];\n } else {\n return [];\n }\n}\n"
}
]
}
My browser JS code then takes this response and creates an instance of this function in that context, like so:
eval("var policyFunction = " + this.policies[j].policyFunction);
policyFailures = policyFunction.call(this, form2js(this.input.closest("form")[0]), this.input.val(), params, this.property.name));
This all works very well. However, I then run this code through JSLint, and I get back this message:
[ERROR] ValidatorsManager.js:142:37:eval is evil.
I appreciate that often, eval can be dangerous. However, I have no idea how else I could implement such a mechanism without using it. Is there any way I can do this and also pass through the JSLint validator?
I wouldn't worry about it since you are only passing these function strings from the server to the client, and are thus in control of what will be evaluated.
On the other hand, if you were going the other direction and doing the evals of client-passed code on the server, that would be an entirely different story...
Update:
As disabling the validation option in your comment may cause you to miss future errors, I would instead suggest passing the function name rather than the entire function and have the function library mirrored on the server and client. Thus, to call the function, you'd use the following code:
var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
var policyArguments = this.policies[j].policyArguments;
policyFunction.apply(this, policyArguments);
Update 2:
I was able to validate the following code with JSLint successfully, which essentially allows you to "turn off" validation for the vast minority of cases where eval is appropriate. At the same time, JSLint still validates normal eval calls, and all uses of this method should throw up flags for future developers to avoid using it/refactor it out where possible/as time allows.
var EVAL_IS_BAD__AVOID_THIS = eval;
EVAL_IS_BAD__AVOID_THIS(<yourString>);
Dont encode a function as a string in JSON. JSON is for content, which you are confounding with behavior.
Instead, I suppose you could return JS files instead, which allow real functions:
{ name : "phoneNumber",
policies : [
{ policyFunction : function() {
whateverYouNeed('here');
}
}
]
}
But while that solves the technical issue, it's still not a great idea.
The real solution here is to move your logic out of your content entirely. Import a JS file full of little validation functions and call them as needed based on a dataType property in your JSON or something. If this functions are as small and portable as you say, this should be trivial to accomplish.
Getting your data all tangled up with your code usually leads to pain. You should statically include your JS, then dynamically request/import/query for your JSON data to run through your statically included code.
I would avoid using eval in all situations. There's no reason you can't code around it. Instead of sending code to the client, just keep it hosted on the server in one contained script file.
If that's not doable, you can also have a dynamically generated javascript file then pass in the necessary parameters via the response, and then dynamically load the script on the client side. There's really no reason to use eval.
Hope that helps.
You can use
setInterval("code to be evaluated", 0);
Internally, if you pass setInterval a string it performs a function similar to eval().
However, I wouldn't worry about it. If you KNOW eval() is evil, and take appropriate precautions, it's not really a problem. Eval is similar to GoTo; you just have to be careful and aware of what you're doing to use them properly.
With very little parsing you could have had it like so:
var body = this.policies[j].policyFunction.substr;
body = body.substr(body.indexOf("(") + 1);
var arglist = body.substr(1, body.indexOf(")"));
body = body.substr(arglist.length + 1);
var policyFunction = new Function(arglist, body);
Which would provide a bit of validation, avoid the literal use of eval and work synchronously with the code. But it is surely eval in disguise, and it is prone to XSS attack. If the malevolent person can get their code loaded and evaluated this way - it will not save you. So, really, just don't do it. Add a <script> tag with the proper URL and that would be certainly safer. Well, you know, better safe then sorry.
PS. My apologises if the code above doesn't work, it only shows the intent, I've not tested it, and if I made a mistake at counting parenthesis or some such - well, you should get the idea, I'm not advertising it by any means.
DRY is definitely something I agree with, however there is a point where copy+pasting is more efficient and easy to maintain than referencing the same piece of code.
The code you're saving yourself from writing seems to be equivalent to a clean interface, and simple boiler plate. If the same code is being used on both the server and the client, you could simply pass around the common pieces of the function, rather than the whole function.
Payload:
{
"name": "phoneNumber",
"type": "regexCheck",
"checkData": "/^\\+?([0-9\\- \\(\\)])*$/"
}
if(payload.type === "regexCheck"){
const result = validPhoneFormat(fullObject, value, payload.checkData)
}
function validPhoneFormat(fullObject, value, regexPattern) {
if (value && value.length && !regexPattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
This would give you the ability to update the regex from a single location. If the interface changes it does need to be updated in 2 places, but I wouldn't consider that a bad thing. If the client is running code, why hide the structure?
If you really, really want to keep both the object structure and the patterns in one place - extract it to a single API. Have a "ValidatePhoneViaRegex" api endpoint which is called by all places you'd be passing this serialized function to.
If all of this seems like too much effort, set jslint to ignore your piece of code:
"In JSHint 1.0.0 and above you have the ability to ignore any warning with a special option syntax. The identifier of this warning is W061. This means you can tell JSHint to not issue this warning with the /*jshint -W061 */ directive.
In ESLint the rule that generates this warning is named no-eval. You can disable it by setting it to 0, or enable it by setting it to 1."
https://github.com/jamesallardice/jslint-error-explanations/blob/master/message-articles/eval.md
I would prefer to see copy+pasted code, a common api, or receiving parameters and copy+pasted boiler plate than magical functions passed in from the server to be executed.
What happens if you get a cross-browser compatibility error with one of these shared functions?
Well, the first thing to bear in mind is that jsLint does make the point that "it will hurt your feelings". It's designed to point out where you're not following best practices -- but code that isn't perfect can still work just fine; there's no compulsion upon you to follow jsLint's advice.
Having said that, eval is evil, and in virtually all cases there is always a way around using it.
In this case, you could use a library such as require.js, yepnope.js or some other library that is designed to load a script separately. This would allow you to include the javascript functions you need dynamically but without having to eval() them.
There are probably several other solutions as well, but that was the first one that came to my mind.
Hope that helps.
I am using this function for easiness, as I am going to use fadeTo a lot:
function fade_to(div, speed, opacity, after_fade) {
$(div).fadeTo(speed, opacity, after_fade);
}
Then I am calling the same function for after_fade parameter:
fade_to('#div', 3000, 1, function() { fade_to('#another_div', 3000, 1)});
Is that a bad thing to do? Will I have speed/smoothness issues?
Is it better to just use jQuery's default fadeTo function?
Thanks!
There is no gain to be made with your method. Plus you are using the jQuery fadeTo function. There is nothing wrong with what you did, just no gain. You could save work with such a technique if for example you had less arguments in your custom function:
function fade_to(div, after_fade) {
$(div).fadeTo(3000, 1, after_fade);
}
fade_to('#div', function(){ fade_to('#another_div', $.noop); });
This would actually save you work by preventing you from having to enter speed and opacity arguments. You could also curry it like this
function Fade_to(speed, opacity){
return function(div, callback){
$(div).fadeTo(speed, opacity, callback);
}
}
Then you could make argument saving functions on the fly like
var fade_to_foo = Fade_to(3000, 1);
fade_to_foo('#div', function(){ fade_to_foo('#another_div'); });
Otherwise there is no reason not to just write it the jQuery way
$('#div').fadeTo(3000, 1, function(){ $('#another_div').fadeTo(3000, 1); });
It's a bad practice because you cannot use any more modifiers without applying them to every instance your function is called. Since you can chain modifiers in jQuery, and most would agree that doing so is a useful feature, you are disabling that useful feature for yourself or anyone else working on this code body.
If you want to add any additional animations or stylings, you'll have to select the object again through regular jQuery this time. Extra work, extra calls, no real benefit.
this practice is against the goal of using jQuery as a chainable, short-syntax library. however if this specific functionality is useful for a project, can be effective.
Mike,
I don't know that this is necessarily a 'bad' thing to do, as it might offer easier usability or something (not sure, given that I don't know the context of your example) that using the standard function given in an API wouldn't otherwise.
Actually, having a function call itself is using an idea in CS called 'recursion' which can be useful for traversing trees (you can google both recursion, and trees to get a better idea of what I'm referring to here), or performing some kind of mathematical operation (i.e. Euclidean algorithm).
I would say, that if you're doing this, it's a great idea to ask "why". You won't be gaining anything in terms of speed since you're passing the parameters an extra time, and your function isn't accomplishing anything extra compared to the API's implementation (at least that I'm seeing). If you were to make a habit out of this...let's say with a more
computationally taxing function...you might notice a slowdown.
I'm hoping to not just answer your question here, but to give you some further insight as to why it's generally a bad idea to do this. I agree with dunsmoreb, and Thomasdotnet as well. Good points!
-sf
Your approach is convenient. I doubt it will slow down the fade effect. There is nothing wrong with this approach in my mind. If you decided that your fade effect should pulse or blink before fading you would only need to modify your function to pulse/blink and then fade all calls to fade would then run the new routine. In this case it makes sense as it reduces code and improves maintainability. Ericosg does make a valid point though why not reduce the paramaters if they are going to be the same.
It is better to just use jQuery's default fadeTo function. just this.