How pass parameters to downstream function with done() or next() - javascript

I am new to next(), done() etc. and am struggling with propagating parameters between serial executions/chaining of possibly otherwise asynchronous functions.
I want to force serial execution of 2 functions so they can be called with something like either:
f1('#{arg1a}', '#{arg1b}').done(
f2('#{arg2a}', '#{arg2b}')
);
OR something like:
f1('#{arg1a}', '#{arg1b}', '#{arg2a}', '#{arg2b}').done(f2);
Where the arg values passed in are gleaned from query parameters using JSF.
Note that:
arg2a and arg2b are in my case completely unrelated to arg1a and arg1b, and the invocation of f2 does NOT depend in any way on what happens in f1, other than it must execute strictly afterwards, even if f1 is otherwise usually asynchronous.
I am not defining on-the-fly anonymous functions or such inside done() here (yet), I want to be able to call a library-defined function with some known params.
In this example, the functions would be something like:
function f1(arg1a, arg1b) {
//do something with arg1a, arg1b
return $.Deferred().resolve();
}
function f2(arg2a, arg2b) {
// Do something with arg2a and arg2b AFTER f1 has fully run.
}
OR something like:
function f1(arg1a, arg1b, arg2a, arg2b) {
//do something with arg1a, arg1b
// Somehow ensure f1 is finished then execute f2(arg2a, arg2b)
}
function f2(arg2a, arg2b) {
// Do something with arg2a and arg2b AFTER f1 has fully run.
}
Just using callback chaining did not work for the situation I am tackling. See also: How link to and target/open a p:tab within an p:accordionPanel within a p:tab within a p:tabview
An acceptable answer MUST permit me to have a pre-defined function f2 with pre-defined parameters

You need to pass parameters to .resolve(), then use .then()
function f1(arg1a, arg1b) {
return $.Deferred(function(dfd) {
//do something with arg1a, arg1b
// you can alternatively call `.resolve()` without passing parameters
// when you are finished doing something with `arg1a`, `arg1b`,
// which should call chained `.then()` where `f2` is called
dfd.resolve(arg1a, arg1b)
}).promise();
}
function f2(arg2a, arg2b) {
// Do something with arg2a and arg2b AFTER f1 has fully run.
}
f1(arg1, arg2)
.then(function() {
// call `f2` here
f2('#{arg2a}', '#{arg2b}');
})
// handle errors
.catch(function(err) { // alternatively use `.fail()`
console.log(err)
});
jsfiddle https://jsfiddle.net/wuy8pj8d/

You've almost got it right except you've forgotten to wrap the code you want to execute in the future (when done is eventually called) inside a function:
f1('#{arg1a}', '#{arg1b}').done(function(){
f2('#{arg2a}', '#{arg2b}')
});
This also works with regular callbacks. For example, say you've defined f1 to accept a callback instead of a promise, you'd then do:
f1('#{arg1a}', '#{arg1b}',function(){
f2('#{arg2a}', '#{arg2b}')
});
Nothing special here. There's no separate syntax for forcing callbacks to accept custom arguments, just wrap it in another function.
This also works for variables thanks to closures:
var a='#{arg1a}', b='#{arg1b}';
var c='#{arg2a}', d='#{arg2b}';
f1(a,b).done(function(){
f2(c,d)
});
The variables c and d will be accessible within done().

Related

What is difference between calling a function and callback function?

What is the difference between following snippets
// calling a function
function execute(){
}
function fn(){
asynchronousFunction(function(){
execute();
})
}
fn();
How the below snippet is different from above
// callback a function
function execute(){
}
function fn(done){
asynchronousFunction(function(){
done();
})
}
fn(execute);
In which way callback is different from calling a function directly? What are pros and cons of each approach?
If you call a function, it will execute immediately.
If you pass the function as an argument to another function, then some other code will call it later (at which point it will execute).
They aren't different approaches for doing the same thing. You use a callback when you are writing a function that needs to do something at some point, but when what that something is depends on something outside the function.
The classic example is addEventListener. For the sake of discussion, let's limit ourselves to click events. You have a standard function for making something happen when something is clicked. Lots of programs want something to happen when something is clicked, but that something can be almost anything.
In first case, your function fn() can see execute() and the parameter is optional, because anytime you call fn() will be called execute().
in second case, you made your function more "general" and you may customize your callback function
The first option presents fn as a simple function that starts some kind of asynchronous action and doesn't present any other information to the outside. If fn is something like uploadData, then you'd have a simple function that tries to upload it (and maybe display an error message if it fails, or a success message when it's done), but the caller can only start it and do nothing else.
The second option additionally allows the caller of fn to decide what should happen when fn completes. So if fn is uploadData, then the caller is able to also specify what should happen once the data has been uploaded (or if there has been an error).
Callbacks like these gives you a lot of flexibility. In your second example, you are able to say: "Do fn(), and do the asynchronous function, and if you have finished, then call done()." And the point is, you can decide what done() does, although you have no insight in the method that calls it.
Delivering functions as an argument, that are to be executed e.g. at the begin, at the end or at other events, is a fundamental principle. It is the basis for hooks, callbacks, promises, configuring of complex objects etc.

Why declaring an anonymous JavaScript function as a function parameter?

I don't understand why some JavaScript frameworks like ember.js use an anonymous function as a function parameter value. I would understand if the function was returning something, but it is not.
Here is a sample code of the routing system of ember.js that demonstrate my question:
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
Please explain me why this code creates an anonymous function as a parameter.
It's because that function .map is an async function, and that anonymous function is what to run AFTER .map completes.
Typically async functions look like:
function async(callback) {
//async stuff, yada
callback();
}
That callback is what you pass in to run once the async operations complete
So basically this creates a way to encapsulate functionality, and run the route set up w/e they need to. I'm not 100% familiar with amber, but my guess is that they do some setup and checking/validation before initializing the routes. Because you pass in the anonymous function, they can now defer the set up you specify until everything is set and ready to go!
A function passed in as a parameter means that the function will be run at some point during (or at the end of) the outer function. Often this is used to pass in a callback function.
For example, the map method might do some stuff and then call the anonymous function when finished:
function map(function) {
// Do some stuff
function();
}

is this callback structured correctly?

I want to save all sections, made updates to questions with IDs for the just saved sections, then save the questions, and then if that is successful fire a function nextPage that redirects the page. I'm trying to confirm this is correct. It seems to act funny if I don't have the anonymous function wrapped around saveAllQuestions.
saveAllSections(function () {saveAllQuestions(nextPage)});
Update:
On the success of saveAllSections it does the following:
if (typeof(callback) == 'function')
callback();
On the success of saveAllQuestions it does the following:
if (questionValuesToSave.length>0) {
saveAllQuestionValues(questionValuesToSave, callback);
}
else {
// once its done hide AJAX saving modal
hideModal();
if (typeof(callback) == 'function')
callback();
}
On the success of saveAllQuestionValues (assuming there are some) it does the following:
if (typeof(callback) == 'function')
callback();
Yes that is a generally correct syntax for a callback, though its hard to know for sure without seeing more code.
The following code
saveAllSections(saveAllQuestions(nextPage));
would fail because saveAllQuestions(nextPage) is the syntax to execute a function, rather than define it. So it will execute that immediately and pass the result to saveAllSections, which will try to use it as the callback. Since this is likely not a function, and almost definitely not the function you want to pass you will get strange behavior, most likely an error.
Wrapping this in an anonymous function means that you're passing a function to saveAllSections, which does not execute until it is called by the outer function or as a callback.
UPDATE:
Looks like saveAllQuestions is also async based on your description, so executing it immediately will definitely not work correctly. The anonymous function wrapper is a completely acceptable solution if you need to pass a param.
If you didn't, you could just use
saveAllSections(saveAllQuestions)
The reason you need to wrap saveAllQuestions in an anonymous function is because otherwise saveAllQuestions gets executed right away, and its return value gets passed as the callback to saveAllSections.
If you wrap saveAllQuestions in an anonymous function, you prevent saveAllQuestions from executing right away.
In javascript, you can pass a function as an argument. This allows for simpler code and asynchronous callbacks. In your attempt, you don't pass a function in. You execute a function, so the result of saveAllQuestions(nextPage) is passed into the function, not the function saveAllQuestions.
Hopefully this example helps.
function add(a,b) {
return a+b;
}
function mul(a,b) {
return a*b;
}
function doMath(num1, num2, op) {
return op(num1, num2);
}
document.write( doMath(4,5, add) ); // 9
document.write( doMath(4,5, function (n1,n2) {return n1+n2;}) ); // 9
document.write( doMath(2,5, mul) ); // 10
document.write( doMath(2,5, function (n1,n2) {return n1*n2;}) ); // 10
document.write( doMath( doMath(1,3, add) , 4, mul) ); // 16

How do you dynamically call a function in Actionscript 3 from Javascript at runtime without using eval()?

I'm trying to build an API in JS that will perform some operations and then execute the callback that's registered in AS when it's done. Because it's an API, I am just providing a JS method signature for another developer to call in Flash. Thus, the callback name that's registered in the AS part of the code should be a parameter that's passed in to the JS API in order for JS to communicate back to Flash.
For example:
[AS3 code]
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", flashCallbackName);
function processRequest(data:String):void
{
//do stuff
}
[JS code]
var namespace =
{
jsFnToCall: function(callback)
{
//Do stuff in this function and then fire the callback when done.
//getFlashMovie is just a util function that grabs the
//Flash element via the DOM; assume "flash_id"'s a global var
//Below does not work...it's what I'd be ideally be doing some how.
getFlashMovie(flash_id).callback(data);
}
};
Because the definition of the function is in AS, I can't use the window[function name] approach. The only way I can think of is to build the callback in a string and then use the eval() to execute it.
Suggestions? T.I.A.
Well, I can think of one thing I would try, and one thing that would work.
What I would try first.
getFlashMovie(flash_id)['callback'](data);
What would work: Have the callback always be the same, say callback. The first parameter to the callback could be used to determine what actual function to call in flash. For example:
function callback($fn:String, $data:*) {
// either
this[$fn]($data);
// or
switch ($fn) {
case "callback1":
DoSomeCallback($data);
break;
}
Additionally passing the objectID makes it a bit simpler:
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", ExternalInterface.objectID, "flashCallbackName");
Then in your JS:
var namespace =
{
jsFnToCall: function(objectID, callback)
{
//Do stuff in this function and then fire the callback when done.
document[objectID][callback](data);
}
};

How does one use $.deferred properly with non-observable functions?

Let's say for example that I have two functions with random code inside and also that based on the user's system (slow, medium, or fast) there is no way to tell how long the two functions will take to complete, so the use of setTimeout is not practical when trying to fire function2 only after function1 is complete.
How can you use jQuery.deferred to make function2 fire only after function1 no matter what the time requirements are, and considering that both functions are 100% non-jQuery functions with no jQuery code inside them and therefore completely un-observable by jQuery? At the very most, the functions might include jQuery methods like .css() which do not have a time association and can run slower on old computers.
How do I assure that function2 is not executing at the same time as function1 if I call them like this:
function1(); function2();
using $.deferred? Any other answers besides those regarding $.deferred are also welcome!
ADDED March 20:
What if function1() is a lambda function where, depending on user input, the function may or may not have asynchronous calls and it is not possible to tell how many operations the function will do? It'd be a function where you wouldn't have any clue as to what would happen next, but no matter what, you'd still want function2 to execute only after everything from the lambda function (function1) is done, no matter how long it takes but as long as the asynchronous aspects are completed. How can this be achieved?
ADDED March 22:
So I guess the only way to do what I'm asking is to pass anonymous functions as callbacks to asynchromous functions that execute the callbacks after they are done, or to create event listeners that will do execute what you want when the event is finally triggered.
There's not really any way to just execute to asynchronous calls on two seperate lines and have them fire in order without manually constructing mechanisms (event handlers) within the frame containing the said functions to handle the actual execution of their actions.
A good example of these types of mechanisms would be jQuery's .queue() method and $.Defferred object.
The answers below along with reading up on jQuery's API on .queue()ing and using $.Deferred helped clarify this.
Tgr gave a great example below on how to create custom chainable functions using jQuery's $.Deferred object, and the custom functions themselves don't necessarily have to have any jQuery code inside them, which is exactly what I was looking for.
function first(deferred) {
// do stuff
deferred.resolve();
}
function second() {
// do stuff
}
$.Deferred(first).then(second);
But as Tomalak pointed out, this is unnecessary, unless you do something very tricky in first (like utilising web workers).
Update:
The basic idea is that whenever you do something that is not immediate, you create a Deferred object, and return that. (jQuery's AJAX calls already do this.) You can then use Deferred.then to delay follow-up operations.
function first() {
var deferred = $.Deferred();
var callback = function() {
deferred.resolve();
}
// do immediate stuff
someAsyncOperation(callback);
return deferred.promise(); // turns the Deferred into a Promise, which
// means that resolve() will not be accessible
}
function second() {
// do stuff
}
first().then(second); // or: $.when(first).then(second)
If second is also an asynchronous operation, you can use $.when's merging capabilities:
function second() {
var anotherDeferred = $.Deferred();
// do stuff with anotherDeferred
return anotherDeferred.promise();
}
$.when(first(), second()).then(third); // third will run at the moment when
// both first and second are done
JavaScript itself is not asynchronous. It is single-threaded, synchronous.
function1();
function2();
will execute one after another unless they contain asynchronous calls. In that case, there will always be a callback you can pass (like onSuccess for XmlHttpRequest). Place the second function there.
To say the truth, they strictly execute one after another even if they contain asynchronous bits. It's just that the asynchronous bits might not yet be finished when the rest of the function is.
EDIT Your jsFiddle example, fixed (see it):
function foo() {
$('#foo')
.html('<span>foo1</span>')
.animate(
{ /* properties */
left: '100px'
},
360, /* duration */
'swing', /* easing */
function () { /* "complete" callback */
$('#foo').append('<span>foo2</span>');
bar();
}
);
}
As I said. There will always be a callback you can pass.

Categories