How to create Semaphore between HTML elements loaded async - javascript

I have in an HTML page, an element that appears several times, and running the same JS.
Problem is, I want it to do a specific function only if it was the first one to run it (his siblings never ran it - YET).
I need semaphore to sync between them.
I am unable to know how to declare a variable and to do semaphore in this way in JS.

There are lots of approaches.
You need to put a flag somewhere. In the absence of anything else, you can put it on window, but use a name that's unlikely to conflict with anything else.
Then the JavaScript is quite straightforward:
if (!window.myUniqueNameFlag) {
window.myUniqueNameFlag = true;
// Do your processing
}
But again, putting things on window is not ideal if you can avoid it, although it's very common practice. (Any variable you declare at global scope with var¹ is a property of window, as is any function you declare at global scope.)
If your function is already declared at global scope (and therefore already occupying a global identifer / window property), you can do this to avoid creating a second identifer. Instead of:
function foo() {
// ...your processing...
}
Do this:
var foo = (function() {
var flag = false;
function foo() {
if (!flag) {
flag = true;
// ...your processing...
}
}
return foo;
})();
That looks complicated, but it's not really: It defines and immediately invokes an anonymous function, within which it defines a variable and a nested function, then it returns the nested function's reference and assigns it to the foo variable. You can call foo and you'll get the nested function. The nested function has an enduring reference to the flag variable because it's a closure over the variable, but no one else can see it. It's completely private.
A third option is to just use a flag on the function object itself:
function foo() {
if (!foo.flag) {
foo.flag = true;
// ...do your processing...
}
}
Functions are just objects with the ability to be called, so you can add properties to them.
¹ Variables declared at global scope with let or const are globals, but do not become properties of window.

Related

Creating a JS function and specifying its scope?

I had a random, rather rudimentary question pop into my head as I was writing some JS about scopes and closures. (Please bear with me with the rather convoluted example.)
Let's say I have two functions, one that's more or less a decorator called "makeMagicFn". This thing takes in an object, looks up the randomFn method on it, and does something cool to it, attaching it as a property to a new object as someSpecialFn, returning the object.
The second function is where that magic happens. It has a few local variables inside of it, and then defines the "random" function for use in the makeMagicFn described above.
Here's the fun part. The randomFn, defined here as innerFn, looks up the variables defined on outerFn's scope (foo and baz), and does some stuff with them. At the end, the decorated innerFn is returned from outerFn to be used by its caller.
function makeMagicFn({ randomFn }) {
const someSpecialFn = makeSomethingAwesomeWithRandomFn(fn);
return {someSpecialFn};
}
function outerFn() {
const foo = "bar";
const baz = "qux";
const insideFn = () => {
console.log(foo, baz);
}
const {someSpecialFn} = makeMagicFn({ randomFn: insideFn });
return someSpecialFn;
}
Now for my question.
Does JS allow me to define innerFn outside of outerFn, in such a way that allows access to outerFn's scope, so it can look up the variables without throwing a ___ is not defined error? (E.g. if I wanted to import it from a separate file instead.) Like using .bind, except setting the context not on outerFn's this, but its place in memory instead.
No, this is not possible. Local variables are local, and scope is lexical. To create a closure over them, you must define the function where they are in scope.
You can do lots of trickery if you don't make foo and baz local variables but properties of an object, which you then can pass around (in the easiest case, as an argument to makeMagicFn).

Checking if an attribute gets attached to $scope

This question really consists of two:
1 - Do functions create their own $scopes in javasript?
e.g.$scope.foo = function() {
$scope.bar = "Bar";
}
I ask this because in one such test that I'm trying to run I check to determine the existence of a variable on the scope, run a function and then recheck:
iit('getPatientFirstName should attach patientName to the scope', function() {
// Passes
expect(scope.patientName).toBeUndefined();
spyOn(scope,'getPatientFirstName').andCallThrough();
scope.getPatientFirstName(detailsBody);
// Fails
expect(scope.patientName)not.toBeUndefined();
});
// In the controller
$scope.getPatientFirstName = function (dataBody) {
$scope.patientName = dataBody.patientFirstName;
};
So this suggests that they may have their own scope? If this is the case can we test this?
2 - Is a valid alternative just to use an object that exists outside the function:
$scope.patientDetails = {
patientName: ''
};
$scope.getPatientFirstName = function (dataBody) {
$scope.patientDetails.patientName = dataBody.patientFirstName;
};
Thanks
EDIT
Considering the two answers has raised another question - is a variable (attribute or object) considered global if its attached to the $scope? It can be accessed in any function in that controller but as far as being called in a completely different controller - yes it can?
Confirm/Deny anyone?
And it appears that assigning the variable to the $scope global is considered valid for the purposes of my test.
Regarding your first questions, no, functions do not create new $scopes by their own (note that we are talking about scopes and not closures, which are two different concepts).
In your example, the $scope.foo function creates a new bar property on the same $scope object where foo is defined. The final $scope object would look something like this:
$scope {
foo: function() {
$scope.bar = "Bar";
},
bar: "Bar"
}
The problem with your test may be related to the missing . before the not.
expect(scope.patientName).not.toBeUndefined();
Is a valid alternative just to use an object that exists outside the
function:
Yes, you can use an object that's defined outside the function.
If the object is on the same $scope object you will have no problems, just make sure it is defined before you run the function, otherwise you will get a $scope.patientDetails is not defined error.
I'll answer the question a little differently than where you are taking it. I hope it helps you to rethink your stategy.
1 - Do functions create their own $scopes in javasript?
They do create an own scope. But the surrounding scope is also available within the scope. So when you write a function within a function, the inner function can use all the variables of the outer function
Example
function foo() {
var a=5;
function bar() {
var b=4;
}
function hello() {
var c=3;
}
}
a is available for all the functions, foo, bar and hello.
b is not available for foo nor for hello.
c is not available for foo nor for bar.
2 - Is a valid alternative just to use an object that exists outside the function:
So, you should try to make an outer function; there you can declare variables that will be strictly contained within that outer function.
Any function you create within this outer function can make use of that outer scope.
Variables that are global should be avoided if possible.
An example: jQuery.
jQuery has 1 variable that is global: var jQuery ( You can also access it by its alias $ ).
The variables that jQuery uses will not be in conflict with any variables you use.
And anything you want from jQuery, you will have to go through $ (or jQuery)

Advanced Javascript initialisation

I'm having trouble deciphering the following Javascript initialisation statement:
(function(NAMESPACE) {
NAMESPACE.nav = {};
var nav = NAMESPACE.nav,
_init = false,
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// constants
nav.CLASS = 'js-nav-open';
nav.CLASS_READY = 'js-nav';
nav.CONTAINER = '#nav';
nav.DURATION = 400;
nav.HAS_CSSTRANSITIONS = $('html').hasClass('csstransitions') && $('html').hasClass('csstransforms3d');
...
...
// toggle open/close
nav.toggle = function(event) {
event.stopPropagation();
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
nav.close();
} else {
nav.open();
}
// this is for the links
if(event) {
event.preventDefault();
}
};
}(PROJECT_NAME));
It seems unnecessarily complicated - calling (or setting?) 'nav' 3 times in 2 lines. Can somebody please explain what the point is of flipping it around like this?
This is an example of a JavaScript closure which is commonly used to create private scope and avoid having the objects pollute the global scope.
It is very common to create plugins this way to avoid conflicts with other functionality on the page as a result of variables with the same name etc. Essentially it's a mechanism for managing scope.
This is a common practice when using jQuery:
(function ($) {
var div = $('#my-div');
// Etc
}(jQuery));
Wrapping your script in a closure ensures that certain variables will have the values you expect them to.
For example, jQuery uses the $ for doing just about everything. Most people like to use $('do something') rather than jQuery('do something').
But say that you have another library on the page that also uses the global variable $.
By wrapping your code in the closure, you "reserve" the $ as jQuery's, and jQuery's alone. (When you pass in jQuery as the argument to closure, $ can only mean "jQuery," in the scope of this function.)
Similarly, in your example, you are reserving the NAMESPACE variable. Even if there were another variable called NAMESPACE, causing a racket somewhere else on the page, by passing in a variable at the end of your closure, you will be guaranteed that NAMESPACE will be the object you expect it to be (at least within the closure).
Say that you had a global variable called AbominableSnowman, but you wanted to use AS as a shortcut. By doing this:
var AS = "Apple Soup";
(function (AS) {
AS.tellMeAboutSnowmen();
alert(AS.snowballs);
}(AbominableSnowman));
Your code will still function as you intended. (Proof: http://jsfiddle.net/RUzZH/1/)
As for "flipping it around," it seems like the original programmer wanted to shorten NAMESPACE.nav down to nav. This was probably the best way of doing that.
An alternative (not recommended):
// It's best to limit your assignments to 1-per-line
// This kind of code isn't fun to debug, or even read
var nav = NAMESPACE.nav = {};
It doesn't seem like something worth fretting over. However, since this script interacts with NAMESPACE.nav quite often, it will be slightly, slightly faster to directly reference the .nav property with the nav variable. (This really is a micro-optimization, but in this case it's conveniently justifiable for a different reason [sake of clarity].)
Here's a line-by-line explanation (with headers just to break it up):
Setup:
// Create an anonymous function expression taking `NAMESPACE` as a parameter.
// Likely the *real* namespace will be passed to the function at the end
// with ... })(realnamespacetomodify);
(function(NAMESPACE) {
// Create the new part of the namespace. Note that we are editing a reference
// so really this change happens on whatever object was passed in.
NAMESPACE.nav = {};
// Create a local pointing to this new sub-namespace. Probably just for
// convenience, also possibly for portability (if the name is used in closures,
// then those closures don't need to refer to NAMESPACE directly).
var nav = NAMESPACE.nav,
Module definition:
// While nav refers to an object likely in global scope, nav itself can
// never be referred to from global scope because it is a local here.
// These variables are local here. They can never be referred to by global scope.
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// These variables, added to nav, can be accessed using the object that
// nav refers to in global scope (see the end).
nav.CLASS = 'js-nav-open';
...
// This function is also added to nav, therefore it can be accessed outside
nav.toggle = function(event) {
...
// This reference to _isNavOpen resolves because this function
// is a closure, and binds variables outside its scope
// to the function itself. So even though _isNavOpen can't be
// accessed globally, it can be accessed here, making it like
// a private member of this namespace.
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
// nav is also bound by the closure and can be accessed here
nav.close();
} ...
};
Use in global space:
}(PROJECT_NAME));
console.log(PROJECT_NAME.nav.CLASS); // "js-nav-open"
console.log(PROJECT_NAME.nav.toggle); // Function object
This is a module pattern. It is used for several reasons:
Code portability (not referring to global objects inside the module)
Scoping (avoiding assigning unnecessary vars to global namespace)
Visibility (hiding private access variables)
As for the first three lines themselves (your original question), they could refer to PROJECT_NAME directly, but it looks like it's been set up to aid code portability. You'll notice that the anonymous function itself never points to the real object (PROJECT_NAME). That means that you can copy and paste this part around and only change that reference in one place.
The other answer mentions scope, and while that's important too, it doesn't explain all benefits of this code, such as why it doesn't just directly refer to existing global variables. The scope-hiding benefits themselves are achieved with this part of the pattern:
(function() {
... // Anything set here is local, not global.
})();

Javascript Function Declaration Options

I've seen experts using below to declare a function:
(function () {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
//etc
}());
e.g.
https://github.com/douglascrockford/JSON-js/blob/master/json.js
Could someone help me understand when should we use above pattern and how do we make use of it?
Thanks.
Well, since ECMA6 hasn't arrived yet, functions are about the best way to create scopes in JS. If you wrap a variable declaration of sorts in an IIFE (Immediately Invoked Function Expression), that variable will not be created globally. Same goes for function declarations.
If you're given the seemingly daunting task of clearing a script of all global variables, all you need to do is wrap the entire script in a simple (function(){/*script here*/}());, and no globals are created, lest they are implied globals, but that's just a lazy fix. This pattern is sooo much more powerful.
I have explained the use of IIFE in more detail both here, here and here
The basic JS function call live-cycle sort of works like this:
f();//call function
||
====> inside function, some vars are created, along with the arguments object
These reside in an internal scope object
==> function returns, scope object (all vars and args) are GC'ed
Like all objects in JS, an object is flagged for GC (Garbage Collection) as soon as that object is not referenced anymore. But consider the following:
var foo = (function()
{
var localFoo = {bar:undefined};
return function(get, set)
{
if (set === undefined)
{
return localFoo[get];
}
return (localFoo[get] = set);
}
}());
When the IIFE returns, foo is assigned its return value, which is another function. Now localFoo was declared in the scope of the IIFE, and there is no way to get to that object directly. At first glance you might expect localFoo to be GC'ed.
But hold on, the function that is being returned (and assigned to foo still references that object, so it can't be gc'ed. In other words: the scope object outlives the function call, and a closure is created.
The localFoo object, then, will not be GC'ed until the variable foo either goes out of scope or is reassigned another value and all references to the returned function are lost.
Take a look at one of the linked answers (the one with the diagrams), In that answer there's a link to an article, from where I stole the images I used. That should clear things up for you, if this hasn't already.
An IIFE can return nothing, but expose its scope regardless:
var foo = {};
(function(obj)
{
//obj references foo here
var localFoo = {};
obj.property = 'I am set in a different scope';
obj.getLocal = function()
{
return localFoo;
};
}(foo));
This IIFE returns nothing (implied undefined), yet console.log(foo.getLocal()) will log the empty object literal. foo itself will also be assigned property. But wait, I can do you one better. Assume foo has been passed through the code above once over:
var bar = foo.getLocal();
bar.newProperty = 'I was added using the bar reference';
bar.getLocal = function()
{
return this;
};
console.log(foo.getLocal().newProperty === bar.newProperty);
console.log(bar ==== foo.getLocal());
console.log(bar.getLocal() === foo.getLocal().getLocal());
//and so on
What will this log? Indeed, it'll log true time and time again. Objects are never copied in JS, their references are copied, but the object is always the same. Change it once in some scope, and those changes will be shared across all references (logically).
This is just to show you that closures can be difficult to get your head round at first, but this also shows how powerful they can be: you can pass an object through various IIFE's, each time setting a new method that has access to its own, unique scope that other methdods can't get to.
Note
Closers aren't all that easy for the JS engines to Garbage Collect, but lately, that's not that big of an issue anymore.
Also take your time to google these terms:
the module pattern in JavaScript Some reasons WHY we use it
closures in JavaScript Second hit
JavaScript function scope First hit
JavaScript function context The dreaded this reference
IIFE's can be named functions, too, but then the only place where you can reference that function is inside that function's scope:
(function init (obj)
{
//obj references foo here
var localFoo = {};
obj.property = 'I am set in a different scope';
obj.getLocal = function()
{
return localFoo;
};
if (!this.wrap)
{//only assign wrap if wrap/init wasn't called from a wrapped object (IE foo)
obj.wrap = init;
}
}(foo));
var fooLocal = foo.getLocal();
//assign all but factory methods to fooLocal:
foo.wrap(fooLocal);
console.log(fooLocal.getLocal());//circular reference, though
console.log(init);//undefined, the function name is not global, because it's an expression
This is just a basic example of how you can usre closures to create wrapper objects...
Well the above pattern is called the immediate function. This function do 3 things:-
The result of this code is an expression that does all of the following in a single statement:
Creates a function instance
Executes the function
Discards the function (as there are no longer any references to it after the statement
has ended)
This is used by the JS developers for creating a variables and functions without polluting the global space as it creates it's own private scope for vars and functions.
In the above example the function f(){} is in the private scope of the immediate function, you can't invoke this function at global or window scope.
Browser-based JavaScript only has two scopes available: Global and Function. This means that any variables you create are in the global scope or confined to the scope of the function that you are currently in.
Sometimes, often during initialization, you need a bunch of variables that you only need once. Putting them in the global scope isn't appropriate bit you don't want a special function to do it.
Enter, the immediate function. This is a function that is defined and then immediately called. That's what you are seeing in Crockford's (and others') code. It can be anonymous or named, without defeating the purpose of avoiding polluting the global scope because the name of the function will be local to the function body.
It provides a scope for containing your variables without leaving a function lying around. Keeps things clean.

Should I encapsulate blocks of functionality in anonymous JavaScript functions?

My intuition is that it's a good idea to encapsulate blocks of code in anonymous functions like this:
(function() {
var aVar;
aVar.func = function() { alert('ronk'); };
aVar.mem = 5;
})();
Because I'm not going to need aVar again, so I assume that the garbage collector will then delete aVar when it goes out of scope. Is this right? Or are interpreters smart enough to see that I don't use the variable again and clean it up immediately? Are there any reasons such as style or readability that I should not use anonymous functions this way?
Also, if I name the function, like this:
var operations = function() {
var aVar;
aVar.func = function() { alert('ronk'); };
aVar.mem = 5;
};
operations();
does operations then necessarily stick around until it goes out of scope? Or can the interpreter immediately tell when it's no longer needed?
A Better Example
I'd also like to clarify that I'm not necessarily talking about global scope. Consider a block that looks like
(function() {
var date = new Date(); // I want to keep this around indefinitely
// And even thought date is private, it will be accessible via this HTML node
// to other scripts.
document.getElementById('someNode').date = date;
// This function is private
function someFunction() {
var someFuncMember;
}
// I can still call this because I named it. someFunction remains available.
// It has a someFuncMember that is instantiated whenever someFunction is
// called, but then goes out of scope and is deleted.
someFunction();
// This function is anonymous, and its members should go out of scope and be
// deleted
(function() {
var member;
})(); // member is immediately deleted
// ...and the function is also deleted, right? Because I never assigned it to a
// variable. So for performance, this is preferrable to the someFunction
// example as long as I don't need to call the code again.
})();
Are my assumptions and conclusions in there correct? Whenever I'm not going to reuse a block, I should not only encapsulate it in a function, but encapsulate it in an anonymous function so that the function has no references and is deleted after it's called, right?
You're right that sticking variables inside an anonymous function is a good practice to avoid cluttering up the global object.
To answer your latter two questions: It's completely impossible for the interpreter to know that an object won't be used again as long as there's a globally visible reference to it. For all the interpreter knows, you could eval some code that depends on window['aVar'] or window['operation'] at any moment.
Essentially, remember two things:
As long as an object is around, none of its slots will be magically freed without your say-so.
Variables declared in the global context are slots of the global object (window in client-side Javascript).
Combined, these mean that objects in global variables last for the lifetime of your script (unless the variable is reassigned). This is why we declare anonymous functions — the variables get a new context object that disappears as soon as the function finishes execution. In addition to the efficiency wins, it also reduces the chance of name collisions.
Your second example (with the inner anonymous function) might be a little overzealous, though. I wouldn't worry about "helping the garbage collector" there — GC probably isn't going to run in the middle that function anyway. Worry about things that will be kept around persistently, not just slightly longer than they otherwise would be. These self-executing anonymous functions are basically modules of code that naturally belong together, so a good guide is to think about whether that describes what you're doing.
There are reasons to use anonymous functions inside anonymous functions, though. For example, in this case:
(function () {
var bfa = new Array(24 * 1024*1024);
var calculation = calculationFor(bfa);
$('.resultShowButton').click( function () {
var text = "Result is " + eval(calculation);
alert(text);
} );
})();
This results in that gigantic array being captured by the click callback so that it never goes away. You could avoid this by quarantining the array inside its own function.
Anything that you add to the global scope will stay there until the page is unloaded (unless you specifically remove it).
It's generally a good idea to put variables and function that belong together either in a local scope or in an object, so that they add as little as possible to the global namespace. That way it's a lot easier to reuse code, as you can combine different scripts in a page with minimal risks for naming collisions.

Categories

Resources