Recently I've been getting into the javascript ecosystem. After sometime with javascript's callbacks I started asking myself if the javascript interpreters are capable of doing conditional evaluation of callback arguments. Let's take the following two example:
var a = 1;
var b = 2;
// example 1
abc.func(a, b, function (res) {
// do something with res
});
// example 2
abc.func(a, b, function () {
// do something
});
From what I understand, Javascript uses the arguments object to keep track of what is passed into a function. This is regardless of what the function definition is. So assuming that:
abc.func = function (a, b, cb) {
// do stuff
var res = {};
// Expensive computation to populate res
cb(res);
}
In both examples (1, 2) the res object will be passed to arguments[0]. In example 1 res === arguments[0] since the res parameter is defined.
Let's assume that computing res is expensive. In example 1 it's ok to go through this computation since the res object is used. In example 2, since the res object is not used, there really is no point in doing that computation. Although, since the arguments object needs to be populated, in both cases the computation to populate res is done. Is this correct ?
Assuming that's true, this seems like a (potentially) huge waste. Why compute something that's going to go out of scope and be garbage collected ? Think of all the libraries out there that use callbacks. A lot of them send multiple arguments back to the callback function, but sometimes none of them are used.
Is there a way to prevent this behaviour. Essentially make the Javascript interpreter smart enough to not compute those specific variables that will turn into unused arguments ? So in example 2 the res object would not actually be computed since it will never actually be used.
I understand that until this point things like this were used:
function xyz(a, b /*, rest */)
// use arguments to iterate over rest
}
So by default it makes sense to still compute those arguments. Now let's look forward to ECMAScript 2015. This will include the ...rest parameter to be defined. So for engines that support the new version, is there a way to enable conditional evaluation? This would make much more sense, since now there is a way to explicitly ask to evaluate and pass in all extra arguments to a function.
No, JavaScript is not a lazy call-by-name language. This is mostly because expressions can have side effects, and the ES standard requires them to be executed in the order the programmer expects them.
Yes, JS engines are smart. If they do detect that code does not execute side effects, and its results are not used anywhere, it just dumps them (dead code elimination). I'm not sure whether this works across function boundaries, I guess it doesn't, but if you are in a hot code path and the call does get inlined, it might be optimised.
So if you know that you are doing a heavy computation, you may want to make it lazy explicitly by passing a thunk. In an eagerly evaluated language, this is typically simply represented by a function that takes no parameters. In your case:
abc.func = function (a, b, cb) {
// do stuff
var res = {};
cb(() => {
// Expensive computation to populate res
return res;
});
}
// example 1
abc.func(a, b, function(getRes) {
var res = getRes();
// do something with res
});
// example 2
abc.func(a, b, function() {
// no heavy computation
// do something
});
You couldn't do that on an interpreter level, it's not feasible to determine whether or not computing a argument was dependent on computing another argument, and even if you could this would create inconsistent behaviour for the user. And because passing in variables into a function is extremely cheap, this becomes a pointless exercise.
It could be done on a functional level - if you wanted to you could pass the expected arguments of the callback as a parameter to the function, thereby augmenting the behaviour of the function based on the parameters, which is commonplace.
Related
Its been a few days that I got to learn about Generator functions in JavaScript which are introduced in ES6 version.
There were various places generators were explained but what seems too intriguing for me is the fact that everywhere it is said that
A generator function is a way to write async code synchronously.
The question that I want to raise is "Why is there so much need to introduce a completely different programming strategy just for the sake of it?"
I understand the async nature of the JS code makes it difficult for a newbie to understand and debug the code but does it require a complete change in coding style altogether?
I maybe wrong or not completely understanding the concept behind its introduction but being inquisitive about it all is what compelled me to ask this question.
Because closures are less convenient for simple iteration; simplifying syntax for reasonably common tasks can be worth it, even if the language supported the same pattern before. Just compare:
function chain() {
var args = Array.from(arguments);
return function() {
if (args.length === 0) return undefined; // Or some other sentinel
var nextval = args[0].shift(); // Destructive to avoid copies or more closure vars
if (args[0].length === 0) args.shift();
return nextval;
};
}
var x;
// a, b and c must be indexable, e.g. Arrays; we can't handle other closures without
// requiring some API specific protocol for generation
for (var nextchain = chain(a, b, c); (x = nextchain()) !== undefined;) {
// do stuff with current value
}
to:
function* chain() {
for (var i = 0; i < arguments.length; ++i)
yield* arguments[i];
}
// a, b and c can be any iterable object; yield* can handle
// strings, Arrays, other generators, etc., all with no special handling
for (var x of chain(a, b, c)) {
// do stuff with current value
}
Sure, the savings in lines of code aren't incredible. It's mostly just reducing boilerplate and unnecessary names, removing the need to deal with closures for simple cases, and with the for...of syntax, providing a common mechanism to iterate arbitrary iterable things, rather than requiring the user to explicitly construct the initial closure and advance it by name. But if the pattern is common enough, that's useful enough.
As noted in comments, a, b, c must be Array-like for the closure based approach (or you'd use a different closure based approach where the writer of chain imposes arbitrary requirements on stuff passed to it, with special cases for Array-like stuff vs. generator-like closures) and processing is destructive (you'd need to add more closure state or make copies to make it non-destructive, making it more complex or slower); for the generator-based approach with yield*, no special cases required. This makes generators composable without complex specs; they can build on one another easily.
Scenario 1 (Async) : You might have heard of the importance of writing “non-blocking” javascript. When we do an I/O operation, we use callbacks or promises in javascript to write non blocking javascript code.
Scenario 2 (Sync): running infinite loop in javascript eg: node -e 'while(true) {}' will possibly freeze your computer
With all of this in mind, ES6 Generators allow us to effectively “pause” execution in the middle of a function and resume it at some time in the future (async code synchronously)
Use case: Imagine you need to do something with a sequence of infinite values. Arrays won’t be helpful in that case instead we could use ES6 generator functions
var iterator = generateRandoms(); //suppose it is a generator function which loops through infinite sequence
//generator functions returns a next function which can be called anytime in your code to get the next value from the sequence
console.log(iterator.next()); // { value: 0.4900301224552095, done: false }
console.log(iterator.next()); // { value: 0.8244022422935814, done: false }
And as far as complexity is concerned, its a new syntax but would not take long to grasp it.
For further reading:
http://x-team.com/2015/04/generators-work/
https://msdn.microsoft.com/en-in/library/dn858237(v=vs.94).aspx
Actually, the generator function is not so much about asynchronous, it is more about a function that can be interrupted, how the flow is interrupted is determined by the caller of generator, through iterator -- more explanation below
function* ab3() {
console.log(1);
var c = yield 2;
console.log(2);
return 1 + c;
console.log(3);
}
a generator function is a function that can be truncated in between
it's execution starts when iterator.next() is called, a generator function returns iterator when called
first call of next will run the statement of generator function till the first yield and it will return the yielded value
second call of iterator.next will run till next yield or return statement
so it will take in the data passed through next(3) // (3 in this example) and store it in variable (variable to which the yield is assigned), var y = yield 2; so 3 will be stored in y; and statement execution till the return statment., it will return {done:true} over here because we have reached the end of the generator function
next execution ( 3rd here) of iterator.next() will return {value: undefined, done:true}, since nothing is further returned by generator function
Say I have a step in a procedure that requires the retrieval of two objects. I would use join() to coordinate the retrievals:
return promise.join(retrieveA(), retrieveB())
.spread(function(A, B) {
// create something out of A and B
});
The documentation shows that you can also pass the handler as the last parameter:
return promise.join(retrieveA(), retrieveB(), function(A, B) {
// create something out of A and B
});
I'm curious as to what the rationale behind the existence of this option.
Fact time: The reason .join was added was to make #spion happy. Not without reason though, using .join means you have a static and known number of promise which makes using it with TypeScript a lot easier. Petka (Esailija) liked the idea and also the fact it can be optimised further because it doesn't have to abide to weird guarantees the other form does have to abide to.
Over time, people started (at least me) using it for other use cases - namely using promises as proxies.
So, let's talk about what it does better:
Static Analysis
It's hard to statically analyse Promise.all since it works on an array with an unknown types of promises of potentially different types. Promise.join can be typed since it can be seen as taking a tuple - so for example for the 3 promises case you can give it a type signature of (Promise<S>, Promise<U>, Promise<T>, ((S,U,T) -> Promise<K> | K)) -> Promise<K> which simply can't be done in a type safe way for Promise.all.
Proxying
It's very clean to use when writing promise code in the proxying style:
var user = getUser();
var comments = user.then(getComments);
var related = Promise.join(user, comments, getRelated);
Promise.join(user, comments, related, (user, comments, related) => {
// use all 3 here
});
It's faster
Since it doesn't need to produce the value of the given promises cached and to keep all the checks .all(...).spread(...) does - it'll perform slightly faster.
But... you really usually shouldn't care.
you can also pass the handler as the last parameter. I'm curious as to what the rationale behind the existence of this option.
It is not an "option". It's the sole purpose of the join function.
Promise.join(promiseA, promiseB, …, function(a, b, …) { … })
is exactly equivalent to
Promise.all([promiseA, promiseB, …]).spread(function(a, b, …) { … })
But, as mentioned in the documentation, it
is much easier (and more performant) to use when you have a fixed amount of discrete promises
It relieves you of needing to use that array literal, and it doesn't need to create that intermediate promise object for the array result.
var f_drum_min = function myself(a){
alert(a);
$f_min_node.push(a);
for (i=0;i<=$m;i++){
if ($f_leg[i][1]==a){
myself($f_leg[i][0]);
}
}
};
myself($f_leg[i][0]); breaks the for loop , how can I make it run multiple times in loop?
Your function is riddled with bad habits
There's no way for me to improve this function because I have no idea what all of those external states do. Nor is it immediately apparent what their data types are.
These are bad habits because there's no possible way to know the effect of your function. Its only input is a, yet the function depends on $f_min_node, $f_leg, and $m.
What is the value of those variables at the time you call your function?
What other functions change those values?
I assigned $f_min_node to some value and then called f_drum_min. How was I supposed to know that $f_min_node was going to get changed?
Every time you call your function, it's a big surprise what happens as a result. These are the woes of writing non-deterministic ("impure") functions.
Until you can fix these problems, recursion in a for-loop the least of your concerns
I have annotated your code with comments here
// bad function naming. what??
var f_drum_min = function myself(a){
// side effect
alert(a);
// external state: $f_min_node
// mutation: $f_min_node
$f_min_node.push(a);
// leaked global: i
// external state: $m
for (i=0;i<=$m;i++){
// external state: $f_leg
// loose equality operator: ==
if ($f_leg[i][1]==a){
myself($f_leg[i][0]);
}
}
};
I can help you write a deterministic recursive function that uses a linear iterative process though. Most importantly, it doesn't depend on any external state and it never mutates an input.
// Number -> Number
var fibonacci = function(n) {
function iter(i, a, b) {
if (i === 0)
return a;
else
return iter(i-1, b, a+b);
}
return iter(n, 0, 1);
}
fibonacci(6); // 8
for loops are pretty primitive; Imperative programmers will reach for it almost immediately thinking it's the only way to solve an iteration problem.
I could've used a for loop in this function, but thinking about the problem in a different way allows me to express it differently and avoid the for loop altogether.
One basic problem with the code, which would cause it to break under almost any circumstances, is that the loop variable i is a global, and is thus shared by all recursive invocations of the function.
For example, let's say the function is invoked for the first time. i is 0. Now it recurses, and let's say that the condition in the if is never true. At the end of the 2nd call, i = $m + 1. When you return to the first call, because i is global, the loop in the first call ends. I assume this is not what you want.
The fix for this is to declare i as local:
for (var i=0;i<=$m;i++){
This may or may not fix all of your problems (as pointed out in comments, we'd have to see more of your code to identify all possible issues), but it is a critical first step.
I quite often have optional arguments in functions, but some testing is showing a huge performance hit for them in firefox and safari (70-95%). Strangely, if I pass in the literal value undefined then there is no penalty. What could be happening here? I wouldn't have thought that it was a scope chain issue as they are inherently local to the function. Am I to start passing undefined into every optional argument?
jsPerf: http://jsperf.com/function-undefined-args/2
For a function like this:
function threeArgs(x, y, z) {
return x + y + z;
}
that's called like this:
threeArgs(1, 2, 3);
the optimizer is free to make the choice to generate no code at all. It's fairly easy for it to determine that there are no side effects, because the function simply references its parameter values and returns the result of a simple expression. Since the return value is ignored, there's no reason for the runtime to do anything at all.
Beyond that, if the code were:
something += threeArgs(1, 2, 3);
the optimizer might decide to generate code roughly equivalent to:
something += 6;
Why? Because the call was made with numeric constants, and it can safely fold those at code generation time. It might be conservative on that, because numbers are weird, but here they're all integers so it could well do this. Even if it didn't, it could safely inline the function:
something += 1 + 2 + 3;
When there's a parameter missing, however, it may be that the optimizers bail out and generate a real function call. For such a simple function, the overhead of the function call could easily account for a large difference in performance.
By using variables instead of constants in a test, and by actually using the return value of the function, you can "confuse" the optimizer and keep it from skipping the call or pre-computing the result, but you can't keep it from inlining. I still think that your result is interesting for that reason: it exposes the fact that (as of today anyway) those optimizers are sensitive to the way that functions are invoked.
I think what could explain the performance difference is the way arguments are passed to a function object: via the arguments object. When not passing any arguments, JS will start by scanning the arguments object for any of the given arguments, when those are undefined, The arguments prototype chain will be scanned, all the way up to Object.prototype. If those all lack the desired property, JS will return undefined. Whereas, passing undefined explicitly, sets it as a property directly on the arguments object:
function foo(arg)
{
console.log(arguments.hasOwnProperty('0'));
}
foo();//false'
foo('bar');//true
foo(undefined);//true
I gather that's the reason why passing undefined explicitly tends to be faster.
I just read through this article on named function expressions and their incompatibilities with IE <= 8.
I'm curious about one statement in particular:
A common pattern in web development is to “fork” function definitions based on some kind of a feature test, allowing for the best performance.
An example taken from his page:
var contains = (function() {
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return function(el, b) {
return (el.compareDocumentPosition(b) & 16) !== 0;
};
}
else if (typeof docEl.contains != 'undefined') {
return function(el, b) {
return el !== b && el.contains(b);
};
}
return function(el, b) {
if (el === b) return false;
while (el != b && (b = b.parentNode) != null);
return el === b;
};
})();
When I see this, my immediate reaction is that this would be terrible to maintain. Code written this way doesn't really lend itself to being easily understandable.
In this case, instead of conditionally defining a function within another function which is then called immediately after the outer function is declared, one could write a function of nested ifs. It would be longer, but in my opinion easier to understand (though I am coming from C/C++/Java).
I would prefer answers that include some test numbers or explanations on how these functions would differ at run time.
It is very efficient. Notice the (); at the very end. This executes and assigns the result of the outer function to contains immediately. It is much more efficient than executing the underlying logic every time that the function contains is used.
Instead of checking each time contains() is called that compareDocumentPosition exists, this is done once when the code first executes. The fact that compareDocumentPosition exists or doesn't exist won't change, so only checking it once is ideal.
Javascript: how much more efficient is forked function declaration?
Barring any magic optimization done with a JIT/run-time it "costs" the same to invoke any function. Functions are just objects that are often stored in variables (or properties).
How much more "efficient" the version that returns a specialized function-object is depends upon factors including (but not limited to):
the number of times the resultant function is executed (1x = no gain) and
the "cost" of the branch vs. other code (depends) and
the "cost" of creating said closure (very cheap)
For a cheap branch or a low number of execution counts the "efficiency" is diminished. If there is a specific use-case, then benchmark that and you will have "the answer".
When I see this, my immediate reaction is that this would be terrible to maintain. Code written this way doesn't really lend itself to being easily understandable.
This example doesn't necessarily do it justice, IMOHO and is messy for other reasons. I think that giving the anonymous outer function an explicit name -- this can be done even for function-expressions -- would help clarify the intent better, for instance. Write code to be clean first. Then run a performance analysis (benchmark) and fix as appropriate. Chance are the "slow parts" won't be what are initially expected.
Some of it "not being easy to understand" is just a lack of familiarity with this construct (not trying to imply anything negative here) -- on the other hand, every language I know of has features which are abused in cases where there are cleaner solutions.
In this case, instead of conditionally defining a function within another function which is then called immediately after the outer function is declared, one could write a function of nested ifs. It would be longer, but in my opinion easier to understand (though I am coming from C/C++/Java).
Again, the exact case is sort of messy, IMOHO. However, JavaScript is not C/C++/Java and functions-as-first-class-values and closures do not exist in C/C++/Java (this is a little white lie, closures can be emulate in Java and the newest C++ supports some form of closures AFAIK -- but I don't use C++).
This construct is thus not seen in those other languages because the other languages do not support it easily (or at all) -- it says nothing about the viability of the approach (in JavaScript or elsewhere) in general.
I would prefer answers that include some test numbers or explanations on how these functions would differ at run time.
See above.
Expanding upon the bold section at top:
A function is "just an object" that is "applied" (read: called) with the (...) operator.
function x () {
alert("hi")
}
x() // alerts
window.x() // alerts -- just a property (assumes global scope above)
a = {hello: x}
a.hello() // alerts (still property)
b = a.hello
b() // alerts (still just a value that can be invoked)
Happy coding.
The main advantage as mentioned is speed. Having a single function with nested ifs means the condition needs to be re-evaluated every time the function is called. However, we know that the results of the conditions will never change.
If you are concerned about readability, a similar effect can be achieved in a more readable way:
var contains = (function () {
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return contains_version1;
} else if (typeof docEl.contains != 'undefined') {
return contains_version2;
} else {
return contains_version3;
}
function contains_version1() {
...
}
function contains_version2() {
...
}
function contains_version3() {
...
}
})();
Or:
(function () {
var docEl = document.documentElement;
var contains =
typeof docEl.compareDocumentPosition != 'undefined' ? contains_version1 :
typeof docEl.contains != 'undefined' ? contains_version2 :
contains_version3;
function contains_version1() {
...
}
function contains_version2() {
...
}
function contains_version3() {
...
}
})();
This is relatively strange construct if you are coming from pure C background, but should be easily to map to known concepts for C++/Java person. This particular sample is essentially implementation base class with abstract function with 3 derived classes implementing it differently for different browsers. Using "if" or "switch" for such case is not exactly the best approach in either C++ nor Java.
Likely set of such functions will be packaged into a "class" and in such case it will closely map to base class with virtual functions and multiple implementations for each browser...