How to synchronize access to private members of a javascript object - javascript

I have a Javascript object created as follows:
var ccStatTracker = (function (){
ccmap:{
"1":["1","2","3","4"],
"2":["4","5"];
}
return {
modifyCCMap: function (){
// Code which takes following actions:
// - adds/removes keys.
// - modifies arrays stored as values against the keys in the map.
}
}
)();
I have a DHTMLXGrid component which displays grid in the form of rows and columns.
When I edit any cell in the grid, "onEditCell" event is called.
Now, I want to call ccStatTracker.modifyCCMap() from an event handler function attached to "onEditCell" event. As I go on modifying the cells, this event will be called asynchronously which will in turn call a function "modifyCCMap" which will modify private member "CCMap" of my Javascript object. So the latest state of my CCMap as seen by two calls might be different right? So what is the best way to handle this? Is there something as "Synchronized" in Javascript as in Java?
Please help me as it will determine the approach we want to take for implementing this.

JavaScript is single-threaded (web-workers aside for a moment), nothing happens asynchronously (or everything for that matter) - all code: event handlers, timeouts, callbacks, etc. - run in the same thread, one after another.
Thus you don't need any synchronization in JavaScript. Any given piece of code in JavaScript is guaranteed to be executed by only a single thread. How cool is that?
See also
JavaScript equivalent of SwingUtilities.invokeLater()
"atomic" operation desturbed by asynchronous ajax callbacks
Are there any atomic javascript operations to deal with Ajax's asynchronous nature?
how is async programming (promises) implemented in javascript? isn't javascript a ui-threaded environment?
...

Related

Create and dispatch events javascript. Code execution simple delegation

Comming from a c# background, I just want to create an event in a certain point of my code, soas to be dispatched elsewere, meaning that if in some part of the code there has been a subscription, this delegate function is called.
So I tried to do:
function myFunction() {
console.log("delegated call achieved!");
}
const myEvent = new Event('onMyConditionIsMet', myFunction, false);
//at this point the program the subscription takes place
function whatever1() {
//...not meaningfull code
myEvent.addEventListener('onMyConditionIsMet');
//myEvent += myFunction; c# way subscription in case it makes sense
}
//at this point in the program, event subscription is checked and
//delegate func run in case there has been a subscription
function whatever2() {
//...not meaningfull code
myEvent?.invoke(); // ?.invoke(); would be the c# way to do it.
}
All the examples I found are related to DOM events, but my case would be for events I create myself, think these are called synthetic events.
Another assumption I make in this question is that there would be no arguments in the delegate call function, so, just to be clear with the naming, it would be a delegate with no arguments. Just pointing this because in c# events are just delegate funcs with no arguments, so a specific type of delegate. Not sure if this works the same way in Javscript.
What would be the approach to do this? (Meaning creating a simple event instance, subscribing, and executing the delegated code if there is any subscription)?
I think the functionality you are looking for can be best obtained by using OOP/Classes.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#prototype_methods
Edit: see this also - "event" is deprecated, what should be used instead?

Javascript - How to fire an event handler immediately rather than queue it

Usually when a javascript event is fired from the code (as far as I know) the event handler is added to a queue, and will only be run after the current code.
(see, e.g., https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)
Now, I have a call to element.blur(), and I want to run the function associated to the blur event imediately, and just after that would execution resume.
I could just call the function, but it was defined by a framework (ionic) and I do not want to mess with its internals, so ideally, I would retrieve the function programatically rather than know its name.
Is is possible? How?
You may call the associated function directly. However, therefore it needs to be in scope:
function onblur(){
this.style.color="blue";
}
document.getElementById("someelem").addEventListener("blur",onblur);
If you want to call it directly:
onblur.call(document.getElementById("someelem"));

NodeJS function getting interrupted by socketio event

I'm seeing some strange behavior in my nodejs game server in which there appears to be concurrency. This is strange because Nodejs is supposed to run in one thread as it doesn't use any concurrency. The problem is that I have an update function that's repeatedly called using setImmediate(). In this function I am using an array in two places. However, this same array is also modified when the "disconnect" event fires (which is when the client disconnects from the server). So it so happens that when the timing aligns so that the disconnect event fires AFTER the first place in which the array is accessed in the update function but BEFORE the second place, the array is modified and so the server crashes when the array is attempted to be accessed in the second place.
Here's some code that might make this picture clear:
function update(){
for(var i = 0; i < gameWorlds.length; i++){
gameWorlds[i].update();
console.log("GAMEWORLDS LENGTH BEFORE: " + gameWorlds.length);
NetworkManager.sendToClient(gameWorlds[i].id, "gameupdate", gameWorlds[i].getState());
console.log("GAMEWORLDS LENGTH AFTER: " + gameWorlds.length);
gameWorlds[i].clearGameState();
}
}
setImmediate(update);
//in the NetworkManager module, the disconnect event handler:
socket.on("disconnect", function(){
for(var a = 0; a < sockets.length; a++){
if(sockets[a].id === socket.id){
sockets.splice(a, 1);
}
}
listenerFunction("disconnect", socket.id);
console.log("Client " + socket.id + " DISCONNECTED!");
});
//also in the NetworkManager module, the sendToClient function:
function sendToClient(clientId, messageName, data){
for(var i = 0; i < sockets.length; i++){
if(sockets[i].id === clientId){
sockets[i].emit(messageName, data);
}
}
}
//in the main module (the same one as the update function), the listener
//function that's called in the disconnect event handler:
function networkEventsListener(eventType, eventObject){
if(eventType === "disconnect"){
for(var i = 0; i < gameWorlds.length; i++){
if(gameWorlds[i].id === eventObject){
gameWorlds.splice(i, 1);
console.log("GAME WORLD DELETED");
}
}
}
}
Now, I have a socketio event listener set up for when the client disconnects in which an element in the array is deleted. When this event occurs RIGHT in between the first and second places the array is accessed (as shown above), my server crashes. Either threads are being used or my function is stopped to let the event handler execute and then my function is resumed. Either way, I don't want this to be happening. Thank you!
EDIT 1: I edited the code to incorporate the console logs I have in my code. The reason why I am saying my loop is getting interrupted is because of the fact that the second console log outputs a length of 0 while the first console log outputs it greater than 0. Also, there is another console log in the disconnect event handler which FIRES in between the two console logs in my update function. This means that my function is getting interrupted.
EDIT 2: Thank you for all your replies I really appreciate it. I think there's been some confusion regarding:
1. The fact that no one has acknowledged how the console logs are appearing. In my previous edit, I changed the code to reflect how I am logging to see the problem. The issue is that in the disconnect event handler, I have a console log which is happening in between the two console logs in the loop. I.e. the disconnect event handler executes BEFORE the second console log is reached in the loop. Unless I am confused about the implementation of the console log function, the logs should be happening in the correct order (that is that the two console logs in the loop should always occur before any other console log in the rest of the program due to the ASYNC nature as most of you have stated.) But this is not the case, which leads me to believe something strange is happening.
2. None of the code inside the loop is changing the array. In a lot of your replies, you assume that there is code which actually modifies the array INSIDE the loop, which is not the case. The only code that modifies the array is code OUTISDE of the loop, which is why it's very strange that the first part of the loop in which the array is accessed doesn't crash but the second part does, even though the code in between DOESN'T change the array.
EDIT 3: Ok so a lot of the replies have been asking for the COMPLETE code. I have update the code with all the relevant REAL code.
Javascript in node.js is single threaded. A given thread of execution in Javascript will NOT be interrupted by a socket.io disconnect event. That physically can't happen. node.js is event driven. When the disconnect event happens, an event will be put into the Javascript event queue and ONLY when your current thread of execution is done will Javascript grab the next event out of the event queue and call the callback associated with it.
You don't show enough of your real code to know for sure, but what could be happening is if you have asynchronous operations, then when you start an async operation and register a callback for its completion, then you are finishing that Javascript thread of execution and it is merely a race to see which async event happens next (the completion of this specific async operation or the disconnect event from the socket.io disconnect). That is indeterminate and those events can happen in any order. So, if you have async code in the code in question, then the disconnect event can get processed while that code is waiting for a completion of an async event.
That is the type of race conditions that you have to be aware of in node.js programming. Anytime your logic goes asynchronous, then other things can get processed in node.js while your code is waiting for the asynchronous callback that signals the operation is complete.
What exactly to do about this depends entirely upon the exact situation and we would need to see and understand your real code (not pseudo code) to know which option to best recommend to you. FYI, this is one of the reasons we can always help you better if you show us your real code, not just pseudo code.
Here are some of the techniques that can be used when you are operating with async operations on a shared data structure that could be changed by other async code:
Make a copy of the data you want to process so no other code has access to your copy so it can't be modified by any other code. This might be making a copy of an array or it might be just using a closure to capture an index locally so the index can't be impacted by other code.
Use a flag to protect a data structure that is in the middle of being modified and train all other code to respect that flag. How exactly to do this depends upon the specific data. I have code in a Raspberry Pi node.js app that regularly saves data to disk and is subject to a race condition where other event driven code may want to update that data while I'm in the middle of using async I/O to write it to disk. Because the data is potentially large and the memory of the system not so large, I can't make a copy of the data as suggested in the first point. So, I used a flag to indicate that I'm in the middle of writing the data to disk and any code that wishes to modify the data while this flag is set, adds its operations to a queue rather than directly modifies the data. Then, when I'm done writing the data to disk, the code checks the queue to see if any pending operations need to be carried out to modify the data. And, since the data is represented by an object and all operations on the data are carried out by methods on the object, this is all made transparent to the code using the data or trying to modify the data.
Put the data in an actual database that has concurrency features and controls built into it so that it can make atomic changes to the data or data can be locked for brief periods of time or data can be fetched or updated in a safe way. Databases have lots of possible strategies for dealing with this since it happens with them a lot.
Make all accesses to the data be asynchronous so if some other async operation is in the middle of modifying the data, then other unsafe attempts to access the data can "block" until the original operation is done. This is one technique that databases use. You do, of course, have to watch out for deadlocks or for error paths where the flags or locks aren't cleared.
Some new comments based on your posting of more code:
This code is just wrong:
//in the main module (the same one as the update function), the listener
//function that's called in the disconnect event handler:
function networkEventsListener(eventType, eventObject){
if(eventType === "disconnect"){
for(var i = 0; i < gameWorlds.length; i++){
if(gameWorlds[i].id === eventObject){
gameWorlds.splice(i, 1);
console.log("GAME WORLD DELETED");
}
}
}
}
When you call .splice() in the middle of a for loop on the array you are iterating, it causes you to miss an item in the array you are iterating. I don't know if this has anything to do with your issue, but it is wrong. One simple way to avoid this issue it to iterate the array backwards. Then calling .splice() will not influence the position of any of the array elements that you have not yet iterated and you won't miss anything in the array.
Same issue in the for loop in your disconnect handler. If you only ever expect one array element to match in your iteration, then you can break right after the splice() and this will avoid this issue and you won't have to iterate backwards.
Two things I think you should change to fix the problem.
1) don't modify the length of the array when disconnect occurs but instead make a value that is falsey. A boolean or a one and zero scenario
2) add logic in the form of an if statement to check if the value is falsey for player two. That way you'll know they disconnected and don't deserve to have anything because they're lame and couldn't watch the loser screen.
That should fix the issue and you can. Decide what to do if they're to lazy to stay and watch the winning losing ceremony of your game.
var gameWorld = [ ];
function update(){ // some code } is async and is pushed to the event loop.
function disconnect(){ // some code } is also async and gets pushed to the event loop.
Even though update() is running on the call stack it's waiting for the event loop and it doesn't mean that it'll complete it's execution before the next tick occurs. gameWorld is outside both scopes it can be modified in the middle of update(). So when update() tries to access the array again it's different then when it started.
disconnect() is called before update() finishes and modifies the array on the event loop nexttick() thus by the time the code for update() gets to second player bam the array is messed up.
Even if you have an event listener, execution should not just stop mid function. When the event occurs, node will push the event callback on to the stack. Then when node finishes executing the current function it will start processing the other requests on the stack. You can't be sure of the order things will execute, but you can be sure that things will not get interrupted mid execution.
If your doWhatever function is async then the problem may be occurring because when node finally gets around to servicing the requests on the stack the loop has already finished, therefore everytime doWhatever is called it is being called with the same index (whatever its last value was.)
If you want to call async functions from a loop then you should wrap them in a function to preserve the arguments.
e.g.
function doWhateverWrapper(index){
theArray[index].doWhatever();
}
function update(){
for(var i = 0; i < theArray.length; i++){
//first place the array is accessed
doWhateverWrapper(i);
....more code.....
//second place the array is accessed
doWhateverWrapper(i);
}
}
setImmediate(update);

Creating a jQuery "object" that is available between _layout and views in ASP.NET MVC

I am coding in ASP.NET MVC 5.2, and using jQuery as my primary script library. I am having a bit of a problem though, with the disparity between _Layout and views that use that layout.
Essentially, it goes like this
_Layout has some script that needs to run (initial wiring, progress bar, splash screen, etc)
Inheriting View has some script that needs to run (unique to that view)
_Layout has additional scripts that need to run after the view's unique scripts.
I have been trying a lot of ways to solve this, but it is actually proving to be a big problem. I have been frequently told that I should not create objects on the global namespace, so I am wondering if there are any other options to creating a script object that I can access in both views that isn't as damaging as global objects.
I have tried promises, and that is getting frustrating. I have tried events, and that doesn't really help because I cannot figure out what to attach the events to. I am told not to attach them to $(document), but that is really one of the only things that will be shared between the view and the layout.
I understand that global objects are not considered good in javascript, but at this point I'm not sure what other options I have to make sure things execute in the right order.
Update
The issue is more about "tooling" than it is about run time. It is true that when the actual view loads and runs, it is all pressed into one big happy page, and would work just fine. The issue is mostly that I have to split up the logic in the tooling (Visual Studio) to keep it from throwing errors and getting confused.
So I suppose it is more accurate to say it is a pseudo-problem.
I have attempted to split up the logic like this, but I think this is just another way of declaring a global object. I got the idea from the Q.js library.
Tasks.js
(function(definition) {
// assign the task system
tasks = definition();
})(function() {
var list = [];
function tasks() {
};
tasks.start = start;
tasks.enqueue = enqueue;
/*
* start the task queue.
*/
function start() {
// make sure to raise a started event for things that need
// to monitor it.
$(this).trigger("started");
};
function enqueue(f) {
// add the potential function to the queue to be processed later.
list.push(f);
$(this).trigger("enqueue", { item: f });
};
return tasks;
});
example usage
$(function(){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
There are a number of ways you could go about this:
Use RequireJs to define Tasks as a module, then:
require(['tasks'], function(tasks){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
Use a global object, but namespace it:
Ciel = Ciel || {};
Ciel.tasks = Ciel.tasks || function(){
var list = [];
...
};
Tie your data to a specific dom element:
<div class="ciel-tasks"></div>
...
$(function() { $('.ciel-tasks').each(function() {
var tasks = $(this);
...
});
It's not really clear what you're describing. From JavaScript's perspective there's no such thing as "_Layout" and "Inheriting View." There's only the resulting DOM delivered to the browser. Any JavaScript code within that DOM can operate on anything else in that DOM. So I'm not sure what any of this has to do with global namespace, events, $(document), etc. Perhaps you're overcomplicating the issue by assuming disparity between your views when, client side, no such disparity exists?
_Layout has additional scripts that need to run after the view's unique scripts.
This sounds like it's just a matter of providing callbacks for operations so that they internally execute in the correct order. For example, if the desired order is:
Layout executes initializeLayout()
View executes initializeView()
Layout executes completeLayout()
Then you can pass these to one another as callbacks and the functions can internally execute those callbacks. So in your Layout you might have something like this at the very top (such as in the header, as long as it's before the view is rendered):
<script type="text/javascript">
function initializeView(){} // placeholder for view-specific initialization
</script>
Then at the bottom with the rest of your scripts:
initializeLayout();
initializeView(completeLayout);
What this does is provide your views with an opportunity to overwrite that initializeView function. If the view defines its own function called initializeView then that one will be executed instead of the placeholder one defined in the layout (remembering that the layout and the view are all one page to JavaScript).
(This also assumes you've elsewhere defined a completeLayout function, since that's what you want to execute after the view is initialized.)
Then in your view you can define that overwriting function:
function initializeView(callback) {
// do some stuff...
if (typeof callback == 'function') {
callback();
}
}
That will execute your view initialization code and then when it's complete will invoke the callback which was provided by the layout, so the layout will then execute its post-view-initialization code. (Naturally, if any of this "initialization" code is asynchronous, you'll want to invoke callbacks in response to those asynchronous callbacks, etc.)

Halt JavaScript execution without locking up the browser

Are you able to halt JavaScript execution without locking up the browser? The way you would normally halt execution is to do an infinite while()-loop, but in the case of FireFox, it locks up the browser until the loop has ended.
What's your take on this?
I am trying to override window.confirm() to implement my own dialog using HTML. I am doing this so I don't have to change existing code (it's a pretty big code-base).
I need to be able to halt execution to allow user-input; to in turn return a boolean like the standard confirm function does:
if (confirm("..."))
{
// user pressed "OK"
}
else
{
// user pressed "Cancel"
}
Update
To my knowledge; this cannot be done using setTimeout() or setInterval() since these functions execute the code thats given to them asynchronously.
confirm() prompt() and alert() are special functions--they call out of the JavaScript sandbox into the browser, and the browser suspends JavaScript execution. You can't do the same thing, since you need to build your functionality into JavaScript.
I don't think there's a great way to drop in a replacement without doing some restructuring along the lines of:
myconfirmfunction(function() {
/* OK callback */
}, function() {
/* cancel callback */
});
Either use callbacks or make your code Firefox-only. In Firefox with support for JavaScript 1.7 and higher, you can use the yield statement to simulate your desired effect. I have created a library for this purpose called async.js. The standard library for async.js includes a confirm method, which can be used as such:
if (yield to.confirm("...")) {
// user pressed OK
} else {
// user pressed Cancel
}
You cannot stop the event thread in JavaScript, so instead you have to work around the problem, usually by using callback functions. These are functions that are run at a later time, but can be passed around like any other object in JavaScript. You might be familiar with them from AJAX programming. So, for example:
doSomeThing();
var result = confirm("some importart question");
doSomeThingElse(result);
Would be converted into:
doSomeThing();
customConfirm("some importart question", function(result){
doSomeThingElse(result);
});
where customConfirm now takes a question and passes the result to the function it takes as an argument. If you implement a DOM dialog with a button, then connect an event listener to the OK and CANCEL buttons, and call the callback function when the user clicks on one of them.
There is an extension to the JavaScript language called StratifiedJS. It runs in every browser, and it allows you to do just that: halting one line of JavaScript code without freezing the browser.
You can enable Stratified JavaScript e.g. by including Oni Apollo ( http://onilabs.com/docs ) in your webpage like:
<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>
Your code would look like this:
var dom = require("dom");
displayYourHtmlDialog();
waitfor {
dom.waitforEvent("okbutton", "click");
// do something when the user pressed OK
}
or {
dom.waitforEvent("cancelbutton", "click");
}
hideYourHtmlDialog();
// go on with your application
the way you normally halt execution should hardly ever be an infinite while loop.
break up your work into parts, that you call with SetTimeout
change this:
DoSomeWork();
Wait(1000);
var a = DoSomeMoreWork();
Wait(1000);
DoEvenMoreWork(a);
to this:
DoSomeWork();
setTimeout(function() {
var a = DoSomeMoreWork();
setTimeout(function() {
DoEvenMoreWork(a);
}, 1000);
}, 1000);
I don't think there's any way to reasonably re-create the functionality of confirm() or prompt() in your own JavaScript. They're "special" in the sense of being implemented as calls into the native browser library. You can't really do a modal dialog of that sort in JavaScript.
I have seen various UI libraries that simulate the effect by putting an element on top of the page, that looks & acts like a modal dialog, but those are implemented using async callbacks.
You will have to modify the existing library, rather than replacing window.confirm.
I tried using tight looping for this. I needed to slow down a native event (which AFAIK is the only use case for a synchronous wait that can't be re-architected asynchronously). There are lots of example loops out there that claim not to lock up the browser; but none of them worked for me (the browser didn't lock up, but they prevented it from doing the thing I was waiting for in the first place), so I abandoned the idea.
Next I tried this - storing and replaying the event, which seems to be impossible cross-browser too. However depending on the event and how flexible you need to be, you can get close.
In the end I gave up, and feel much better for it; I found a way to make my code work without having to slow down the native event at all.

Categories

Resources