I am looking through someone else's code and keep seeing functions written in this style:
getConsents: (_, callback = () => {}) => {
const data = {};
callback(data, true);
}
I'm aware some use the underscore as a convention for skipping a parameter when it's not appropriate, though I cannot make sense of why the callback function parameter is written in this manner.
I tried using babel to see if it made anymore sense in es5, though was out of luck:
getConsents: (function (_) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var data = {};
callback(data, true);
});
If someone could explain this convention, or detail what it this is doing, it would be much appreciated.
Since ES6 you can specify default values for function parameters. For example:
function greet(name = 'John Doe') {
console.log('hello', name);
}
greet('Alan Alda');
greet();
The function in your example is defaulting the callback parameter to an empty function. That way it can blindly call it without checking for undefined first.
In ES5 it might look something like:
getConsents: (function(_, callback = function() {}) {
const data = {};
callback(data, true);
})
It's just setting a default value for the callback.
Related
I'm trying to understand exactly how this Once function by David Walsh works:
`
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
`
I understand it takes a function as a argument, and returns a function that calls the passed function only once.
But I'm trying to understand what each part is doing. Can anyone help explain? especially this part:
result = fn.apply(context || this, arguments);
Why the OR sign? what is "this" and how is it getting the arguments from fn? What purpose does 'context' serve?
I wrote a similar once() function for school that returns the result of the passed function, and stores the result to return it again if the function attempts to get called again. It took a lot of trial and error, and I'm just trying to get a firm grasp on all the component parts of how this works.
`
function add(x, y) {
return x + y;
}
function once(fn) {
let timesRan = 0;
let result;
function doOnce() {
if (timesRan === 0) {
timesRan = 1;
result = fn.apply(this, arguments); //I don't understand how this gets the arguments from AddOnce
console.log(`did it once: ${result}`)
return result;
} else {
return result;
}
}
return doOnce;
}
var addOnce = once(add);
console.log(addOnce(1, 2)); // test first call, expected value: 3
console.log(addOnce(2, 5)); // test second call, expected value: 3
console.log(addOnce(8, 22)); // test third call, expected value: 3
`
The concept behind this in JavaScript is confusing, because when I write a function such as:
function getPersonName() {
return this.name
}
I expect that this be defined as a some object with a name attribute. Depending on the scope, I may have this be defined and no problems! But in order for a function such as the above to properly reference this, we need to tell it what it should reference when we use that keyword.
For example, it allows us to do the following:
var canOnlyFireOnce = once(function() {
console.log(this.name)
}, {name: "John"});
canOnlyFireOnce() // prints John
canOnlyFireOnce() // nada
It may be helpful to understand the bind function's use cases in JavaScript to understand why having this (no pun intended) is useful.
The meaning of the this context in function.apply is already explained in rb612's answer.
For the question about arguments, you need to know that
the arguments object is a local variable available within all non-arrow functions. You can refer to a function's arguments inside that function by using its arguments object.
I set up a callback function inside my Meteor async method to be called on "readable" event. But the callback is not being called when the on."readable" is being fired (I know it's being fired from the console.log I set up).
Am I missing something here? I've been at it for a few hours now trying a few different things!
Meteor.startup(() => {
Meteor.call("getfeed", function(feedloader) {
//I get: TypeError: undefined is not a function]
console.log(feedloader);
});
});
Meteor.methods({
getfeed: function(callb) {
var req = request('http://feeds.feedburner.com/Techcrunch');
var feedparser = new FeedParser();
testing = [];
//........a bunch of functions........
feedparser.on('readable', function() {
var stream = this
, meta = this.meta
, item;
while (item = stream.read())
{
//I'm pushing the results into testing var
testing.push(item);
}
//From the logs I can see that this is called 12 times
//but the callback's not firing!!!
console.log(testing.length);
callb(testing);
});
}
});
Meteor methods are not asynchronous functions in the sense that they do not get the callback argument even though you pass it when you "call" a method. Instead each method is executed within a Fiber which is another flavor of dealing with asynchronous code.
Fortunately, Meteor has a nice helper that allows you to mix both styles. What you need to do is wrap the "pure" asynchronous part of your method code with Meteor.wrapAsync. This structure should look more or less like this:
Meteor.methods({
getfeed: function() {
var wrapped = Meteor.wrapAsync(function (callb) {
var feedparser = new FeedParser();
testing = [];
// ...
feedparser.on('readable', function() {
// probably the same code you have, but without "callb()"
});
feedparser.on('end', function () {
// NOTE: No error here, so the first argument must be null.
callb(null, testing);
})
});
// NOTE: Finally, call the wrapped function
return wrapped();
}
});
I have a function like this one (simplified) :
doSmthg (name, age, callback) {
callback(name, age);
}
I'd like to have a default value for age if it's not provided.
I know I could do doSmthg(name, callback, age=42) {...} in ES6 but I've been told callback should always be the last parameter as it make the call to the function more readable.
For now the solution I found is to do the following :
doSmthg (name, age, callback) {
if (arguments.length === 2) {
age = 42;
callback = age;
}
}
But I find this solution hard to read.
Is this the good solution ? Is there a better one ?
For this kind of situation you can use something like this:
function doSmthg(name, age, callback) {
if (typeof age === 'function') {
callback = age;
age = DEFAULT_VALUE;
}
//continue
}
Or you can use a Hash of options, that i think it's better because makes the code more readable, depending of the number of parameters:
function doSmthg(options, callback) {
var name = options.name;
var age = options.age || DEFAULT_VALUE;
//continue
}
doSmthg({ name: 'batman' }, function() {});
Also you can use the underscore #extend function to merge the options with the default values.
If you have access to spread operator:
function foo(...args) {
const callback = args.pop();
const [name, age = 42] = args;
// ...
}
But I think it's time to use promises in NodeJS as well.
function foo(name, age = 42) {
return new Promise(resolve => {
setTimeout(() => resolve({name, age}), 1000);
});
}
//...
foo('Sándor').then(x => console.log(x)); // { name:"Sándor", age:42 }
Using ES6 promises you can get rid of the so called "callback pyramid", and makes it possible to use your function with ES7 async-await keywords. The future is here!
Code
function foo(args, callback){
parsed = {name:"John Doe",age:12}; //default values
for(a in args) parsed[a] = args[a];
//Arguments are accessible like parsed.name
callback(parsed);
}
function callback(args){
alert(JSON.stringify(args));
}
foo({name:"Peter",extra:2},callback);//yields {"name":"Peter","age":12,"extra":2}
foo({name:"Mark",age:92},callback); //yields {"name":"Mark","age":92}
foo({},callback); //yields {"name":"John Doe","age":12}
Explanation
Depending on the number of arguments to pass it might look too verbose to your liking. The concept should be self explanatory but to put it in words, we group the arguments in an object and inside the function have an object with the default values (if needed). Then we override the defaults with those passed leaving us a very clear and clean callback and verbose args.
Note that if extra parameters are passed, those are not lost in the process of setting the defaults.
I'm wondering if there is a way to implement a generic "memoize" functional (as in a function with a function as input and a function as output, as python's decorators) capable of handling also cps-style functions.
for a normal function (as in "the result value comes back by the return, the parameters are only for input!") a memoize function can be as simple as (in javascript)
function memoize(fun) {
var cache = {};
return function () {
var args = Array.prototype.slice.call(arguments);
if (args in cache)
return cache[args];
var ret = fun.apply(this, arguments);
cache[args] = ret;
return ret;
};
}
but a cps-style function cannot be memoized by my simple memoize function, cause I need to evaluate "again" the arguments of type function, knowing also the parameter to pass to them.
For example, given the function
function cps(param, next) {
var ret = param + 1;
// setTimeout for simulate async behaviour
setTimeout(function () {
next(ret);
}, 0);
}
maybe I can find that next is a function, but its signature (well... maybe, but it's tricky), and definitely not the parameters used in the function!
Can someone tell me I'm wrong? :D
I'm interested to be able to memoize an half dozen of cps-style functions and I don't want to mess with the logic inserting a "cache" in every one of them.
I'm new to CPS, but I think you'll have to construct your functions in a particular way.
Your CPS functions have the following structure (generalising from your example):
function cps(param, next) {
var ret = someFunctionOfParam(param);
// setTimeout for simulate async behaviour
setTimeout(function () {
next(ret);
}, 0);
}
So, you could use your standard memoizer, and construct the CPS function as well. Keeping this separate for the sake of it, first the CPS-maker (assumes the last argument for the functions is always the function to pass to):
function cpsMaker(transformFunc) {
return function() {
var args = Array.prototype.slice.call(arguments);
var next = args.pop(); // assume final arg is function to call
var ret = transformFunc.apply(this,args);
// setTimeout for simulate async behaviour
setTimeout(function () {
next(ret);
}, 0);
}
}
And then the memoizer can be used in conjunction with it:
function plusOne(val) {
return val+1;
}
var memoPlusOne = memoize(plusOne);
var cpsMemPlusOne = cpsMaker(memoPlusOne);
cpsMemPlusOne(3,function(n){console.log(n)});
The point is to separate the memoization of the transform from the CPS construction.
Thank you for introducing the idea of memoized CPS; even if this answer is rubbish, it has been an eye-opener for me!
I'm trying to go through the source code for the node chat demo seen here. In the server.js file and fu.js file there is a function referenced as callback() seen here:
function loadResponseData(callback) {
if (body && headers && !DEBUG) { //if they already have value
callback();
return;
}...
but as far as I can tell this function is never defined and I cannot find it as a module function of node.js, a function of jquery or a standard function for javascript.
I think I understand how callback functions work but I'm not familiar with this call and it is used frequently enough in this app that I would like a firm understanding of what it is and where it comes from.
So my question is three fold:
1) where is the function based: (javascirpt, jquery, node.js, particular to this app)
2) where can I find the source code for this function?
3) how is this function interacting with the functions it is called in?
It is the argument of the loadResponseData function. If you call loadResponseData like this:
loadResponseData(function () {
res.writeHead(200, headers);
res.end(req.method === "HEAD" ? "" : body);
});
then callback() in loadResponseData will execute
res.writeHead(200, headers);
res.end(req.method === "HEAD" ? "" : body);
EDIT to clarify the question in comments:
You could say it's a feature of JavaScript. The important thing here is that JavaScript is a functional language: it has functions as a data type in their own right. Thus, you can save them in variables (and indeed, that's all every function name in JS is - a variable with a function as its content), and pass them along in an argument list (as is demonstrated here). There is nothing magical about the name callback - it could have as well been fn or whoopsie7. To demonstrate:
var doubleAndOne = function(a) {
return a * 2 + 1;
}
function doItTwice(k, whoopsie7) {
whoopsie7(whoopsie7(k));
};
doItTwice(5, doubleAndOne); // result is 23
function(...) {...} is called an anonymous function: it is pure function value, taking some arguments and doing something with them, but it is not assigned to any name. To make a function with a name, you can assign this to a variable, or pass it as a parameter, just like you could with any other value. For example, there is very little difference between:
var five = function() { return 5; };
var doubleFuncValue = function(fn) { return fn() * 2; };
doubleFuncValue(five); // result 10
and
var five = 5;
var doubleNumValue = function(n) { return n * 2; };
doubleNumValue(five); // result 10