I'm looking to have better flow control for this async waterfall function.
async.waterfall([
async.apply(osxAppIconName, options.appFile),
function(iconFileName, callback) {
var existingIcon = path.join(options.iconDirectory, iconFileName);
return callback(null, existingIcon);
},
async.apply(fs.copy, options.iconFile), //automatically puts in existingIcon
async.apply(osxAppIconTouch, options.appFile),
], callback);
Right now I'm using async.apply which will inject global function arguments. In this case above I'm good, it takes existingIcon and will add it as the second-to-last argument in fs.copy. Making fs.copy's arguments options.iconfile, exitingIcon, callback [function]. Which is great!
However, let's say I need exitingIcon later on. Let's say I push this into my waterfall functions array.
async.apply(newFunction, existingIcon)
How would I get existingIcon to this function? Globals? It seems like a headache to manage! I also think that the async.apply function is executing on load, so if I pass it a variable it's gonna use the value of the variable when async.apply executes.
Thoughts? I have a proposal for async.switchboard here. Which attempts to solve this, but it doesn't work.
There's a nifty way around this using async.auto which attaches the result of a function to a prop in the chain.
return async.auto({
"icon_name": async.apply(osxAppIconName, options.appFile),
"copy_icon": ["icon_name",
function(callback, results) {
results.existing_icon = path.join(options.iconDirectory, results.icon_name);
return fs.copy(options.iconFile, results.existing_icon, callback);
}
],
"touch_icon": ["copy_icon", async.apply(osxAppIconTouch, options.appFile)],
}, callback);
For promises check out:
https://github.com/reggi/promise-ripple
https://www.npmjs.com/package/promise-auto
Related
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().
I come from a C/C++ background and I'm having real trouble trying to wrap my head around the syntax of node.js. Anyway, I found some code online to explain the difference between blocking and non-blocking code, and it's had me stumped for hours. I've tried searching and reading books but just can't find an answer to this. The example code retrieves a user ID from a database.
Blocking Version:
function getUser(id) {
var user = db.query(id);
return user;
}
console.log('Name: ' + getUser(432).name);
Non-Blocking Version (Node.js):
function getUser(id, callback) {
db.query(id, callback);
}
getUser(432, function (user) {
console.log(user.name);
});
I'm fine with the Blocking version because in that instance, the user ID is assigned to the variable user. What I just can't seem to understand is the user argument in the anonymous function. It seems that user just appears out of nowhere and then has instructions acted upon it, without any relationship to an existing variable.
How does the program know what user is? How does it even make any connection with the user's ID? I honestly can't tell if it's my lack of knowledge of JavaScript/Node, or whether the person who wrote this code didn't bother to complete it. All I know is, this makes no sense in C/C++.
Well, you've asked the program to fetch you a user, and supplied with a function that accepts an argument (or more, depending on the library). After the operation is complete, getUser will invoke the callback you passed with the result of the operation.
Here's a dummy getUser implementation for you:
function getUser(id, callback) {
setTimeout(function() {
var result = {id: id, name: "Madara"};
callback(result);
}, 1000); // Wait a second before doing it. Asynchronous!
}
getUser(42, function(user) { console.log(user); });
That function will wait one second, and then invoke the callback you pass with one argument, in this case, an object with the ID you passed, and "Madara" as the name.
Notice that there's nothing blocking with getUser, so getUser returns immediately, and without waiting for the callback to be called.
Maybe it will help you if I translate your example into C.
I haven't used C in a long time but I think it would look like this.
void getUser(int id, void (*callback)(User)) {
db.query(id, callback);
}
void printUserName(User user) {
printf(user.name);
}
getUser(432, &printUserName);
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.
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();
}
I know it's maybe an fairly easy basic knowledge for you, here I need to ask your help to see whether there is a 'hole' behind to improve. Please check the code below, can I set 'response' as callback parameter but not callSvc's? instead of this kinda 'tricky' way?
function callSvc(response, callback){
callback(response);
}
callSvc("I'm a response!",function(param_response){document.write(param_response);});
Thanks..
Update
Maybe this is good enough?
function callSvc(callback) {
callback("response");
}
callSvc(function(data) {
document.write(arguments[0]);
});
There shouldn't be anything tricky about closures in javascript. They are a language feature.
You can avoid the wrapping callSvc function as well, and jump straight into this:
var response = "I'm a response"
var callback = function(){document.write(response);};
The callback function can "see" response as if you passed it as a parameter, since it forms a closure.
callback(); //I'm a response
Eh? All that code looks to be the equivalent of
document.write("I'm a response!");
So you can bypass all the methods. You can also declare an anonymous function and call it immediately, if that's what you wanted to do:
(function(param_response){document.write(param_response);})("I'm a response!");
Or lastly, if you need to pass parameters to a callback that doesn't except any, then wrap it in an anonymous funciton
func_that_takes_callback(function(){the_real_callback(arg);});
Instead of defining your callback anonymously define it before hand:
function callSvc(response, callback){
callback(response);
}
function cb(param_response) {
document.write(param_response);
}
Then you can use it in a call to callSvc or on its own:
callSvc("I'm a response!", cb);
cb("I'm a response!");