Javascript - Arguments Vs Nested functions Vs Performance - function

Javascript noob question - which one of the following is best practice and performance friendly, also welcome any other suggestions too. This is simplest version of original project. There will be 20+ variables and 10+ inner functions (Ex: 'process' in the case).
The advantage of Method 1 is it doesn't need to send arguments to the functions but as it nests all the functions inside the main function (possibly regenerate all the inner function for each instance of Foo). While the method 2 is free from function nesting but requires lot of arguments. Note that also there will be multiple instance of Foo constructor.
Method 1:
function Foo () {
var a = 1;
var b = 2;
var c = (a+b)/2;
var $element = $('#myElement');
var process = function (){
var x = a+b+c;
$element.css('left', x)
return x;
}
x = process ();
}
Method 2:
function Foo () {
var a = 1;
var b = 2;
var c = (a+b)/2;
var $element = $('#myElement');
x = process (a, b, c, $element);
}
function process (a, b, c, $element){
$element.css('left', x)
return x;
}

The separated functions are definitely the way to go for performance. While there are situations where the variable scoping of nested functions would be nice to have, the performance hit can be huge if the function is large.
Keep in mind that every time Foo if called, var process is reallocating all the memory for the new function that is being created, rather than keeping the function in memory and just passing it new parameters. If the function is big, this is going to be a pretty intense task for the Javascript interpreter.
Here are some hard numbers that may help as well (Contains performance comparisons and actual benchmarks that you can run in your own browser): http://jsperf.com/nested-functions-speed, http://jsperf.com/nested-named-functions/5

Actually browsers do optimize even nested functions to where performance differences compared to functions declared in outer scope become negligible.
I blogged my findings and created a performance test to support this claim.
EDIT: The test was broken, after fixing the test shows that it's still faster not to nest functions.

Related

Is there a way to make a function call within a where construct?

I would like to do something like:
Real a(10)
Real b(10)
! define a and b, then
where (a<b)
a = f1(a,b)
elsewhere
a = f2(a,b)
endwhere
function f1(a,b)
! somehow or another operates only where a < b
end function f1
function f2(a,b)
! somehow or another operates only where a>=b
end function f2
I guess I could do something like
a = f1(a,b)
a = f2(a,b)
function f1(a,b)
where (a<b) ...
end function f1
function f2(a,b)
where (a>=b) ...
end function f2
but I thought the way I am trying to puzzle out would be nice to have in some ways. Is there a way to do this?
In response to some comments, I want to operate on a by calling already defined functions that has too many lines of code to fit nicely here. I can't discuss the functions, but let's say, for instance that they rely on some kind of convergence loop:
function f1(a,b)
real a(10), b(10)
real f1(10)
real tmp(10), conv
real tol = 1.e-5
tmp = a
f1 = sin(b*a)
conv = max(abs(f1-tmp))
while (conv > tol)
tmp = f1
f1 = sin(b*tmp)
conv = max(abs(f1-tmp))
endwhile
return
end function
And there are ways to improve this and the math might be such that it won't converge etc. etc., but this is an example that gets at what I am talking about. The thing is, I want it to operate only on the domain defined by the where construct. Thanks.
In the case where f1 and f2 are nonelemental functions these functions are evaluated based on all elements of the argument arrays.
However, for an elemental function f1 or f2 only those elements of a and b matching a true mask will be processed (elementally).
Looking at your example function, an elemental function wouldn't be suitable, so you'll have to use an alternative approach. If you can phrase the function with a where construct wrapping the whole thing, though, you may be in luck with elementals.

What is the use case for var in ES6?

If the let keyword introduces a proper implementation of block scope, does var any longer have a use case? I am looking at this from a software design standpoint rather than a syntactical, "well you could" standpoint.
If the let keyword introduces a proper implementation of block scope, does var any longer have a use case?
There could be one use case: let declarations in global scope don't create a property on the global object. Example:
"use strict"; // for chrome
var foo = 42;
let bar = 21;
console.log('window.foo (var)', window.foo); // 42
console.log('window.bar (let)', window.bar); // undefined
From 8.1.1.4 Global Environment Records
The object Environment Record component of a global Environment Record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative Environment Record component of the global Environment Record.
However, this can also easily be solved by creating an explicit global variable using by assigning to the global object directly:
window.foo = 42;
This would also be the only way to create global classes btw, because the class declaration has the same behavior.
(Note: I'm not advocating the use of global variables)
There are syntax constructs where you can only use var, but that's more a consequence of the how the spec evolved and doesn't really serve any practical purpose. For example:
if (true)
var foo = 42; // valid but kind of useless or bad design
// vs
if (true)
let foo = 42; // invalid
Block scope is not the only useful feature though. The temporal dead zone is another handy feature to find bugs more easily. Compare:
var foo = 42;
function bar() {
console.log(foo); // undefined
var foo = 21;
}
bar();
// vs
var foo = 42; // or `let`, doesn't matter
function bar() {
console.log(foo); // ReferenceError, temporal dead zone
let foo = 21;
}
bar();
You get a reference error when trying to access a let variable that wasn't initialized yet.
let can't be used in global scope yet. var can.
This is what you get from Chrome when you try a global let outside of strict mode:
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
Practically there may be some use-cases.
1. Declare variable in try-catch like so:
try {
//inits/checks code etc
let id = getId(obj);
var result = getResult(id);
} catch (e) {
handleException(e);
}
//use `result`
With let the result declaration would be before try, - a bit early and out of context.
2. Same for conditional declarations:
if (opts.re) {
var re = new RegExp(opts.re);
var result = match(re);
if (!result) return false;
}
// result is available here
With let this code would be forced to complain "good style", though that might be impractical.
3. Loop block:
for (var x = 0; x < data.width; x++) {
if (data[x] == null) break;
//some drawing/other code
}
//`x` pointing to the end of data
Some may consider that untidy, I myself prefer lets, but if code I already has vars - that's natural to keep using them.
You can use var if you want to deconstruct something into the function scope, for example a conditional:
if (Math.random() > 0.5)
var {a,b} = {a: 1, b: 2}
else
var {a,b} = {a: 10, b: 20}
// Some common logic on a and b
console.log(a, b)
With let you would have to write something like
let result;
if (Math.random() > 0.5)
result = {a: 'foo', b: 'bar'}
else
result = {a: 'baz', b: 'qux'}
// Using const might make more sense here
let {a, b} = result;
// Some common logic on a and b
console.log(a,b)
Don't Throw Out var
Stylistically, var has always, from the earliest days of JS, signaled "variable that belongs to a whole function." var attaches to the nearest enclosing function scope, no matter where it appears. That's true even if var appears inside a block:
function diff(x,y) {
if (x > y) {
var tmp = x; // `tmp` is function-scoped
x = y;
y = tmp;
}
return y - x;
}
Even though var is inside a block, its declaration is function-scoped (to diff(..)), not block-scoped.
While you can declare var inside a block (and still have it be function-scoped), I would recommend against this approach except in a few specific cases. Otherwise, var should be reserved for use in the top-level scope of a function.
Why not just use let in that same location? Because var is visually distinct from let and therefore signals clearly, "this variable is function-scoped." Using let in the top-level scope, especially if not in the first few lines of a function, and when all the other declarations in blocks use let, does not visually draw attention to the difference with the function-scoped declaration.
In other words, I feel var better communicates function-scoped than let does, and let both communicates (and achieves!) block-scoping where var is insufficient. As long as your programs are going to need both function-scoped and block-scoped variables, the most sensible and readable approach is to use both var and let together, each for their own best purpose.
There are also other semantic and operational reasons to choose var or let in different scenarios.
WARNING:
My recommendation to use both var and let is clearly controversial and contradicts the majority. It's far more common to hear assertions like, "var is broken, let fixes it" and, "never use var, let is the replacement." Those opinions are valid, but they're merely opinions, just like mine. var is not factually broken or deprecated; it has worked since early JS and it will continue to work as long as JS is around.
Where To let?
My advice to reserve var for (mostly) only a top-level function scope means that most other declarations should use let. But you may still be wondering how to decide where each declaration in your program belongs?
POLE already guides you on those decisions, but let's make sure we explicitly state it. The way to decide is not based on which keyword you want to use. The way to decide is to ask, "What is the most minimal scope exposure that's sufficient for this variable?"
Once that is answered, you'll know if a variable belongs in a block scope or the function scope. If you decide initially that a variable should be block-scoped, and later realize it needs to be elevated to be function-scoped, then that dictates a change not only in the location of that variable's declaration, but also the declarator keyword used. The decision-making process really should proceed like that.
If a declaration belongs in a block scope, use let. If it belongs in the function scope, use var (again, just my opinion).
Why use var for function scoping? Because that's exactly what var does. There literally is no better tool for the job of function scoping a declaration than a declarator that has, for 25 years, done exactly that.
You could use let in this top-level scope, but it's not the best tool for that job. I also find that if you use let everywhere, then it's less obvious which declarations are designed to be localized and which ones are intended to be used throughout the function.
By contrast, I rarely use a var inside a block. That's what let is for. Use the best tool for the job. If you see a let, it tells you that you're dealing with a localized declaration. If you see var, it tells you that you're dealing with a function-wide declaration. Simple as that.
function getStudents(data) {
var studentRecords = [];
for (let record of data.records) {
let id = `student-${ record.id }`;
studentRecords.push({
id,
record.name
});
}
return studentRecords;
}
The studentRecords variable is intended for use across the whole function. var is the best declarator to tell the reader that. By contrast, record and id are intended for use only in the narrower scope of the loop iteration, so let is the best tool for that job.
In addition to this best tool semantic argument, var has a few other characteristics that, in certain limited circumstances, make it more powerful.
One example is when a loop is exclusively using a variable, but its conditional clause cannot see block-scoped declarations inside the iteration:
function commitAction() {
do {
let result = commit();
var done = result && result.code == 1;
} while (!done);
}
Here, result is clearly only used inside the block, so we use let. But done is a bit different. It's only useful for the loop, but the while clause cannot see let declarations that appear inside the loop. So we compromise and use var, so that done is hoisted to the outer scope where it can be seen.
The alternative—declaring done outside the loop—separates it from where it's first used, and either necessitates picking a default value to assign, or worse, leaving it unassigned and thus looking ambiguous to the reader. I think var inside the loop is preferable here.
There are other nuances and scenarios when var turns out to offer some assistance, but I'm not going to belabor the point any further. The takeaway is that var can be useful in our programs alongside let (and the occasional const). Are you willing to creatively use the tools the JS language provides to tell a richer story to your readers?
Don't just throw away a useful tool like var because someone shamed you into thinking it wasn't cool anymore. Don't avoid var because you got confused once years ago. Learn these tools and use them each for what they're best at.
Source: YDKJS by Kyle Simpson

How can I optimise this method?

I have been working on creating an assets class that can generate dynamic TextureAtlas objects whenever I need them. The specific method is Assets.generateTextureAtlas() and I am trying to optimise it as much as possible as I quite frequently need to regenerate texture atlas's and was hoping to get a better time than my 53ms average.
53ms is currently costing me about 3 frames which can add up quickly the more items I need to pack inside my texture atlas and the frequency I need to generate them. So an answer to all the pitfalls within my code would be great.
The entire class code is available here in a github gist.
The RectanglePacker class is simply used to pack rectangles as close together as possible (similar to Texture Packer) and can be found here.
For reference, here is the method:
public static function generateTextureAtlas(folder:String):void
{
if (!_initialised) throw new Error("Assets class not initialised.");
if (_renderTextureAtlases[folder] != null)
{
(_renderTextureAtlases[folder] as TextureAtlas).dispose();
}
var i:int;
var image:Image = new Image(_blankTexture);
var itemName:String;
var itemNames:Vector.<String> = Assets.getNames(folder + "/");
var itemsTexture:RenderTexture;
var itemTexture:Texture;
var itemTextures:Vector.<Texture> = Assets.getTextures(folder + "/");
var noOfRectangles:int;
var rect:Rectangle;
var rectanglePacker:RectanglePacker = new RectanglePacker();
var texture:Texture;
noOfRectangles = itemTextures.length;
if (noOfRectangles == 0)
{
return;
}
for (i = 0; i < noOfRectangles; i++)
{
rectanglePacker.insertRectangle(Math.round(itemTextures[i].width), Math.round(itemTextures[i].height), i);
}
rectanglePacker.packRectangles();
if (rectanglePacker.rectangleCount != noOfRectangles)
{
throw new Error("Only " + rectanglePacker.rectangleCount + " out of " + noOfRectangles + " rectangles packed for folder: " + folder);
}
itemsTexture = new RenderTexture(rectanglePacker.width, rectanglePacker.height);
itemsTexture.drawBundled(function():void
{
for (i = 0; i < noOfRectangles; i++)
{
itemTexture = itemTextures[rectanglePacker.getRectangleId(i)];
rect = rectanglePacker.getRectangle(i, rect);
image.texture = itemTexture;
image.readjustSize();
image.x = rect.x + itemTexture.frame.x;
image.y = rect.y + itemTexture.frame.y;
itemsTexture.draw(image);
}
});
_renderTextureAtlases[folder] = new TextureAtlas(itemsTexture);
for (i = 0; i < noOfRectangles; i++)
{
itemName = itemNames[rectanglePacker.getRectangleId(i)];
itemTexture = itemTextures[rectanglePacker.getRectangleId(i)];
rect = rectanglePacker.getRectangle(i);
(_renderTextureAtlases[folder] as TextureAtlas).addRegion(itemName, rect, itemTexture.frame);
}
}
Well reading the project & finding what all can be optimized would sure take time.
Start by removing multiple calls to rectanglePacker.getRectangle(i) inside loops.
For example :
itemName = itemNames[rectanglePacker.getRectangleId(i)];
itemTexture = itemTextures[rectanglePacker.getRectangleId(i)];
rect = rectanglePacker.getRectangle(i);
perhaps, could have been:
rect = rectanglePacker.getRectangle(i);
itemName = itemNames[rect];
itemTexture = itemTextures[rect];
If getRectangle does indeed just 'get a rectangle' & not set anything.
I think the bigger issue at hand is this, why oh why do you HAVE to do this during run-time, in a situation when this can't take more time? This IS an expansive operation, no matter how much you optimize this you will probably end up with it taking about 40ms or similar when done in AS3.
This is why these kind of operations should be done during compile time or during "loading screens" or other "transitions" when frame-rate is not critical and when you can afford it.
Alternatively create another system in c++ or some other language which can actually handle the number-crunching that gives you the finished result.
Also, when it comes to checking performance, yes the entire function takes 53ms, BUT, where are those milliseconds used? 53ms says nothing and is only the "overhead profiling thing" where you found the culprit, you need to break it down into smaller chunks to gather some reliable information about what it is that ACTUALLY takes time, inside that function.
I mean, inside that function, you have 3 for loops, several calls to other classes, casts, deletes, creations. It's not like you are doing one thing, that function probably results in ~500 lines of code and a bazillion cpu operations. And, you have no idea where it is used. I would guess that it is the rectanglePacker.packRectangles(); that takes 60% of that time, but without profiling, you and we don't know on what to optimize, we simply don't have sufficient data.
If you HAVE to do this during run-time in AS3, I would recommend doing this spread out during several frames and distributing workload evenly during 10 frames or so. You could also doing it with help of another thread and workers. But most of all, this seems like a design error since this could probably be done at another time. And if not, then in another language which is better at these kind of operations.
The easiest way to profile this is to add a couple of timestamps similar to:
var timestamps:Array = [];
And then push getTimer() at different places in code, and then print them out when function is done
As others said, it's unlikely that the reason of bad performance is non-optimized AS code. Output from the profiler (Scout, for example) wold be very helpful. However, if your purpose is just adding new textures, I can suggest several optimizations:
Why would you need to re-generate the whole atlas every time (calling Assets.getTextures() and creating new render texture)? Why don't you just add new items to the existing atlas? Creation of a new RenderTexture (and, thus, a new texture in GPU memory) is very costly operation, because it requires sync between CPU and GPU. On the other hand, drawing into RenderTexture is carried out entirely inside GPU, so it takes much less time.
If you place every item on a grid, then you can avoid using RectanglePacker as all of your rectangles can have the same dimensions matching the dimensions of a grid.
Edit:
To clarify, some time ago I had a similar problem: I had to add new items to the existing atlas on a regular basis. And the performance of this operation was quite acceptable (about 8ms on iPad3 using 1024x1024 dynamic texture). But I used the same RenderTexture and the same Sprite object that contained my dynamic atlas items. When I need to add a new item, I just create new Image with desired texture (stand-alone or from another static atlas), then place it inside the Sprite container, and then redraw this container to the RenderTexture. Similarly with deletion/modification of an item.

MATLAB function syntax within script?

Having some trouble declaring functions within my script:
%Read the raw audio data
refData = wavread('file1.wav');
userData = wavread('file2.wav');
% I want to continue writing my "main" function here, and call the below functions
%%%%%%%%%%%%%
% Functions %
%%%%%%%%%%%%%
%Vector x
function preEmphasis(x)
alpha = 0.95;
len = length(x);
for i=1:len
x_i = x(i);
x_iMinus1 = x(i-1);
x(i) = x_i - alpha*x_iMinus1;
end
end
%Vector x
function normalization(x)
maxVal = max(abs(x));
x = x / maxVal;
end
%Vector x; numFrames, frameSize: integers; stepSize: percentage (float, 0.2 -> 0.5 for example)
function Ymatrix = createYmatrix(x, numFrames, frameSize, stepSize)
Ymatrix = zeros(numFrames, frameSize);
for i=1:numFrames
for j=1:frameSize
Ymatrix(i,j) = x(stepSize*i + j);
end
end
end
The words "function" and "end" are highlighted in red as "parse errors". How can I fix this? Thanks.
You can't declare functions within your main script. You have to create an external m-file and implement your function inside it, like it says in the official documentation:
Any function that is not anonymous must be defined within a file.
(just to be clear, a script does not accept input arguments or return output arguments).
However, you can have local functions declared inside a function m-file.
Read more about function declarations in the official documentation.
EDIT: You can Refer to #natan's answer if you're looking for a way to avoid function m-files altogether. He implemented your functions as anonymous functions, which can be declared inside the script file. Good luck!
In Addition to what Eitan mentioned, here is how to implement an anonymous functions in your case, note that code vectorization is a must. For example, in your case instead of normalization you can write:
normalization = #(x) x./max(abs(x));
and then use it as if it was a function, y=normalization(x)
For preEmphasis:
preEmphasis= #(x) [x(1) x(2:end)-0.95*x(1:end-1)];
Your current code has a bug for the case i=1 so I interpret that as for=2:len instead;
The solution for Ymatrix is a bit ugly (haven't invested to much time vectorizing it nicely), but it should work:
Ymatrix = #(x, numFrames, frameSize, stepSize) ...
ones(1,numFrames)'*x(1+stepSize:stepSize+frameSize)+...
meshgrid(0:stepSize:stepSize*numFrames-1,ones(1,frameSize))';
Just turn your script into a function; then you can use local and nested functions. Use return values or assignin if you need to get values back in to the base or caller's workspace.

Bogus math with app scripts

Anyone had an issue with bogus math results when using Google Apps Script? The following is the code, where a/b/c are send from another function. A/b/c are verified with the logger. ? StartPt is fine, but endpt is generating a false value.
function calcTime(a,b,c) {
var x;
var startHr = 8;
var startMin = 0;
var startSec=0;
var startPt;
var endPt;
startPt = (startHr * 60) + startMin + (startSec/60);
endPt = (a * 60) + b + (c/60);
Logger.log(endPt);
x = endPt -startPt;
return x;
}
flag
I found that the math error is a multiplication factor of 100 (when endPt is calculated, it multiplies the result by 100). What could cause this?
Real number arithmetic is prone to rounding errors in javascript and apps-script. See Is floating point math broken?. If you're watching your function in the debugger, you'll see rounding errors esp. with (c/60). But that's not likely causing a factor-of-100 error.
Most likely, your parameters aren't what you thing they are. If b arrives as a string, for instance, the calculation of (a * 60) + b + (c/60) will effectively ignore b. The other two parameters, however, will get changed to numbers to to complete the multiplication and division operations. (You can avoid that by using b * 1.)
Anyway, to confirm what you're getting as parameters, try replacing the first few lines of your function with this:
function calcTime(a,b,c) {
var params = {
a:{type:typeof a, value:a},
b:{type:typeof b, value:b},
c:{type:typeof c, value:c}}
Logger.log(params);
var x;
...
Verify that you're getting what you need. If any of the parameters are arriving as date objects, for instance, your math will be wildly incorrect. You may just need to enforce types for your data source.