Does JSVM run just in one thread?
I am wondering how the JavaScript function executing inside the VM.
The source code below is interesting:
// include jQuery as $
function test() {
$.ajax({url:"xxx.com"})
.success(function() {alert("success 1");})
.fail(function() {alert("fail 1");});
$.ajax({url:"yyy.com"})
.success(function() {alert("success 2");})
.fail(function() {alert("fail 2");});
while(true);
}
It will make die loop at the "while" line and never pop up any alert dialog to show neither "success" nor "fail".
We know inside the $.ajax, the VM creates XMLHttpRequest and sends a HTTP request.
After sending out two requests, it meets the "while" line.
Thus I image that the JSVM:
1) can handle only function call at one time. (function is atomic)
2) follow the rule: first comes, first served.
Does my idea right?
Does anyone can explain the internal implementation of JSVM?
More specific,
If using AngularJS to develop a front end app, we would like to do something and then immediately record a log to remote server in form submit event like ng-submit.
function ngSubmitTest() {
doA();
recordA(ajax, remoteServer); // must after doA()
}
If recordA uses AJAX, we should ensure recordA is complete before ng-submit redirect the page meanwhile kill the old page and also the VM (if the old page is killed, the recordA may not complete). One solution is doing AJAX with async=false. And I wonder if there is any other solutions?
Thanks.
The implementation of JS depends on the context you're runing it.
Each browser has it's own implementantion, and they can do whatever they want as long as they follow the language specification.
It shouldn't bother you if it runs on one or multiple threads, but you can be sure JavaScript is not a "threaded" language, it works with an event loop flow, in which an event is fired, and consecutive functions are fired after that, until there is nothing more to call. This is the reason why it's pretty hard to block the UI in JavaScript if you're writing "good" code.
A good example on how this works, and the diferences betwen event loops and classic threading, is node.js, i'll give you a example:
Supose you're listening for a request on a server, and 2 seconds after the request arrives you'll send a message. Now let's supose you duplicate that listener, and both listeners do the same thing. If you request the server, you'll get the two messages at the same time, 2 seconds after the request is made, instead of one message on 2 seconds, and the other one on 4 seconds. That means both listeners are runing at the same time, instead of following a linear execution as most systems do.
Node runs Chrome's V8 if you're wondering, it's a very professional JS interpreter and it was a breakthorugh when it came out.
Related
How to prevent new EventSource from missing first messages before addEventListener called (in pure vanilla JS)?
The problem is race condition between start data receiving and handler subscribing due to non atomic operation create-subscribe.
It would be nice to have a way to create EventSource in closed state or pass subscribers right into constructor.
I can see two workarounds:
to have additional API to notify server that listeners are ready or to request first data after subscribers set
to add some sleep timeout in server before initial data transfer.
They both are ugly enough to not even try to use SSE and go to WebSocket. But it's another question.
I faced this situation trying to create EventSource and subscribe in Chrome Console. So, there was a lag in seconds between creation and adding a listener. Yes, in real life in script the lag will be near milliseconds, but it still exists.
And that was the cause of your problem; the entire reason you experienced it was because you entered each line manually through the console. You cannot expect code entered that way to behave the same as code running sequentially in the browser directly. In "real life" the problem does not exist because the time between statements is less than milliseconds, but more than that, the code is synchronous and is blocking the event loop, so incoming events will not ever be missed in that situation. To have closer to realistic behavior from the console you will need to paste both the creation and listener assignment statements as a single block at the same time. If you do that, you will see that no events are ever missed.
Disclaimer. A friend of mine looking for a job of senior JS programmer sent the question to me. It's not a real problem then, but since I can imagine where and how it could become real, I've decided to post it here.
The question (a test task). It follows in my words, I can quote it here, if you think I got it wrong. How to write a function which sends asynchronously requests to a given array of URLs, concatenates the result of each request and returns the concatenated string? Oh, and there is another limitation: IE9+, current FF, current Chrome. The friend's answer (as polite as possible): no can do.
My answer was the same. Since there are no threads in browser JS (it's not NodeJS) and there is no sleep function, you cannot wait until all requests are processed. Web workers? They aren't supported in IE9. Also, they wouldn't help anyway. You can send the requests one-by-one, using sync flag of XMLHttpRequest.open but (here is my suggestion) if all requests are being sent to the same server which does some math that can be executed on a single CPU core only, your penalty is x4/x8/x16 times. Anyway, it's prohibited by the test task. Of course, you can concatenate the results in a callback function, but it's prohibited as well, since you must return the result.
But I'm not a JS guru, so I forwarded the question to my another friend who is (I think so). He suggested creating additional browser tabs, one per URL, which would send the request and write the result in its title. The main tab would loop thru the tabs, waiting until all the titles aren't empty. Since the tabs are executed independently, it should work. Then he tried the solution and said it works in IE only (with some side effects). In other words, no solution.
But the employer replied to my first friend with a statement the solution exists, though refused to send JS code of the function.
So, is the question a some kind of trolling? Or there is a solution I will be able to use if I ever face a situation when I really MUST concatenate async requests results (I know it's a bad idea in JS).
Here's a discussion of various options:
Use synchronous Ajax and return the result. Synchronous ajax is a horrible idea and the challenge said to use async requests so presumably this is a no-go, but I include it here because it does let you directly return the result.
If you use async ajax in the same window, then you simply cannot return the result directly. You can call a callback when the result is done or you can return a promise which will then call a .then() handler callback when the result is available. You cannot spin and wait for the async ajax to finish because the Ajax complication can't get back to you until you return and let the event queue get to the next events.
If you put Ajax into a webWorker (either synchronous or asynchronous), you can code the webWorker however you want, but the only way it can communicate back to the main thread is via a message and that message can't be received by the main thread until you return back from your original function to get to the next messages in the event queue. Again, you can't spin and wait for the message from the webWorker because it won't get back to you until AFTER the current thread of execution finishes. So, you have to return from your function BEFORE you can get the result from the webWorker.
You can put the Ajax into an iFrame or another window and then communicate back to the current window from the other window when it is done. This has all the same issues as the previous solutions in that you won't be able to receive communication back from the iFrame or other window until after the current function has finished and returned so that events can get processed off the event queue. So, you have to return from your function BEFORE you can get the result from another window.
You can put the Ajax into an iFrame or another window and then poll some variable in that window from your main window. There is a possibility that this might work in some browsers, but I was unable to build a successful test to prove it could work.
1st thought:
function concatenatesResults(urls, cb) {
var temp = [], i = urls.length
urls.forEach(function (url, key) {
//its async so not block the foreach
$.ajax({
url: url,
success: function (data) {
temp[key] = data //be sure it is in a good order
i--
if (i === 0) cb(temp.join("")) //if this is teh last one return the data
}
})
})
}
concatenatesResults([/* URLS*/], function(data){console.log(data)})
I have some slow OData calls which need to present some sort of visual indicator to the user that something is happening.
I've read the API reference and seen functions like attachRequestSent(), setBusy(), BusyDialog, BusyIndicator, etc.
I tried using them accordingly but did not work for me. The problem seems to be oModel.create causing the whole app to hang while it executes. No loading indicators or anything can run since the app is frozen until the create function has returned.
Edit: I have set up an asynchronous batch read OData call. I have then wrapped the code for handling the received data in a function and called that function inside the success function in the batch call.
This works; the view loads and I see a busy indicator before the fields are populated with the data
oModel.submitBatch(/*fnSuccess*/);
Is this a good way to do it, or is there a better way which is more standard?
Before the Odata call, display the busy indicator (locks the entire app screen). with
sap.ui.core.BusyIndicator.show(0);
Then, in both the success and failure handlers of the odata call, hide it with
sap.ui.core.BusyIndicator.hide();
It does not work with implicit calls (when for instance you bind to an odata model), for this you can use the request sent events, but the idea is the same.
Edit: You also need to give a small delay to allow the indicator to appear, then use setTimeout to call your odata after a small delay.
doStuffWithIndicator: function(){
sap.ui.core.BusyIndicator.show(0);
setTimeout(function(){
doStuff();
sap.ui.core.BusyIndicator.hide();
}, 20);
},
checkout this thread: SAPUI5 Wait for an Deferred-Object // wait for .done() function
Javascript is asynchrone, this means the code will be processed further no matter if you make an call (which might take longer). Therefore before calling an OData Service you need to tell your JS to wait for it (make it synchrone) via an deferred object.
The main problem seems to be oModel.create causing the whole app to hang while it executes. No loading indicators or anything can run since the app is frozen until the create function has returned.
Sounds like you've been using the now-deprecated sap.ui.model.odata.ODataModel the whole time, which sends mostly synchronous XHRs. Synchronous XHRs block the main thread (== UI thread) until the browser receives the response. The browser isn't then able to update the DOM to display the busy indicator during the round trip.
If anyone reading this has the same issue, please migrate to the newer equivalent model: sap/ui/model/odata/v2/ODataModel. It sends only asynchronous requests (AJAX), allowing the UI thread to handle other tasks (such as adding the busy indicator to the DOM) while the browser waits for the response.
I have a script that pings a series of urls with a GET method. I only want to ping them each once and do not expect a response. My script works in Chrome and Safari, but Firefox won't complete the later requests.
Is there a way to trigger Firefox to make a series of calls (five, to be precise) once each, and not care if they fail? It seems that Firefox won't complete the series of requests when the first ones fail.
I'm working in javascript and jQuery, with a little jQuery.ajax() thrown in. I've searched, to no avail and have reached the limit of my beginner's skill set. Any insight would be appreciated.
(If you're interested in the full scope, there's code at jquery-based standalone port knocker)
Thank you.
Update:
After further research, I believe the issue is that Firefox isn't handling the calls truly asynchronously. I have versions of code making the pings with img calls, iframe url calls, and ajax calls to work in Chrome and Safari, but in Firefox they're not behaving as I need them to.
Our server monitoring for the knock sequence should see requests come sequentially to ports 1, 2, 3, 4, 5 (as it does when using Chrome or Safari) but in Firefox, no matter which method I've tried, I see the first attempt ping port 1 twice, then port 2, and on subsequent attempts I only see it ping port 1. My status updates appear as expected, but the server isn't receiving the calls in the order it needs them. It seems that Firefox is retrying failed calls rather than executing each one once, in sequence, which is what I need it to do.
Here is a sample of my script using a simple jquery.ajax call method. It works in Safari and Chrome, but doesn't achieve the desired result in Firefox. While all my code runs and I can see the status updates (generated with the jquery.append function), the request aren't sent once each, sequentially to my server.
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('button').click(function(){
$('#knocks').append('<p>Knocking...</p>');
setTimeout(function(){
$.ajax({url: 'https://example.sample.com:1111'});
$('#knocks').append("<p>Knock 1 of 5 complete...</p>");
}, 500);
setTimeout(function(){
$.ajax({url: 'https://example.sample.com:2222'});
$('#knocks').append("<p>Knock 2 of 5 complete...</p>");
}, 3500);
setTimeout(function(){
$.ajax({url: 'https://example.sample.com:3333'});
$('#knocks').append("<p>Knock 3 of 5 complete...</p>");
}, 6500);
setTimeout(function(){
$.ajax({url: 'https://example.sample.com:4444'});
$('#knocks').append("<p>Knock 4 of 5 complete...</p>");
}, 9500)
setTimeout(function(){
$.ajax({url: 'https://example.sample.com:5555'});
$('#knocks').append("<p>Knock 5 of 5 complete...</p>");
}, 12000);
setTimeout(function(){
$('#knocks').append("<p>Knocking is complete... <br>Proceed to site: <a href='http://example-url.sample-url.com'>http://example-url.sample-url.com</a></p>");
}, 13000);
});
});
</script>
Seeing there's no real answer to your question and you'd probably want to move on, I though I'd give you some suggestions as a starting point.
For your function calls to truly execute in a sequential order (or synchronous, in-order, blocking,...) you will have to make sure you issue all the subsequent function calls (AJAX requests in your case) once the proceeding requests completed (either succeed, or failed, in which case you might not want to proceed with the next in-order call and issue a completely separate response).
The way you're doing it now isn't considered synchronous, instead it is actually asynchronous, delayed (or 'in the background' with a timeout). This might cause all kinds of problems when you expect your AJAX calls to execute synchronously (blocking) at your server end. From browsers re-issuing failed or timed-out requests (for various reasons, depending on their feature set and how they handle failed requests, caching,...) to preemptively issuing requests and caching results when some pre-fetchers are enabled (or however they're calling it in FF), then re-issuing them again if pre-fetcher failed. I believe this is similar to what you observed in Firefox and might be the main culprit for this unexpected behavior. As you can't control what features end user enables or disables in their browser, or what new features they implement in future versions, you can't really expect your server calls to execute asynchronous by delaying their calls with setTimeout, even if they appear to be doing so in other browsers (probably because of your server responding fast enough for them to appear as such).
In your code, the second call would only appear to be executing synchronously (waiting for the first one to complete) for up to half a second, the third request for up to 3 seconds and a half, and so on. But even if setTimeout was blocking execution (which it doesn't), which external request would it be waiting for? The first one, or the second one? I think you get what I'm trying to say and why your code doesn't work as expected.
Instead, you should either issue subsequent AJAX calls through your server's response (which is actually the point of using AJAX, otherwise there's no need for it), or preferably, create an external listener function that will handle these calls according to the status and/or return values of your previous external calls. If you need to handle failed requests as well and continue execution regardless, then the external listener (with preset execution stack timeout) is the way to go, as you obviously wouldn't be able to depend on response of failed requests.
You see, browsers have no problems issuing multiple concurrent requests and delaying them with setTimout doesn't stop pre-fetchers to try and cache their responses for later use either. It also doesn't issue requests in a blocking manner, the next one waiting for the previous one to finish, as you expected them to. Most will be happy to utilize up to a certain number of concurrent connection (~10 on client machines, a lot more on servers) in an effort to speed-up the download and/or page rendering process, and some obviously have even more advanced caching mechanism in place for this very same reason, Firefox being merely one of them.
I hope this clears things up a bit and you'll be able to rewrite your code to work as expected. As we have no knowledge of how your server-side code is supposed to work, you'll have to write it yourself, though. There are however plenty of threads on SE discussing similar techniques that you might decide on using, and you can always ask another question if you get stuck and we'll be glad to help.
Cheers!
I have seen this link: Implementing Mutual Exclusion in JavaScript.
On the other hand, I have read that there are no threads in javascript, but what exactly does that mean?
When events occur, where in the code can they interrupt?
And if there are no threads in JS, do I need to use mutexes in JS or not?
Specifically, I am wondering about the effects of using functions called by setTimeout() and XmlHttpRequest's onreadystatechange on globally accessible variables.
Javascript is defined as a reentrant language which means there is no threading exposed to the user, there may be threads in the implementation. Functions like setTimeout() and asynchronous callbacks need to wait for the script engine to sleep before they're able to run.
That means that everything that happens in an event must be finished before the next event will be processed.
That being said, you may need a mutex if your code does something where it expects a value not to change between when the asynchronous event was fired and when the callback was called.
For example if you have a data structure where you click one button and it sends an XmlHttpRequest which calls a callback the changes the data structure in a destructive way, and you have another button that changes the same data structure directly, between when the event was fired and when the call back was executed the user could have clicked and updated the data structure before the callback which could then lose the value.
While you could create a race condition like that it's very easy to prevent that in your code since each function will be atomic. It would be a lot of work and take some odd coding patterns to create the race condition in fact.
The answers to this question are a bit outdated though correct at the time they were given. And still correct if looking at a client-side javascript application that does NOT use webworkers.
Articles on web-workers:
multithreading in javascript using webworkers
Mozilla on webworkers
This clearly shows that javascript via web-workers has multithreading capabilities. As concerning to the question are mutexes needed in javascript? I am unsure of this. But this stackoverflow post seems relevant:
Mutual Exclusion for N Asynchronous Threads
Yes, mutexes can be required in Javascript when accessing resources that are shared between tabs/windows, like localStorage.
For example, if a user has two tabs open, simple code like the following is unsafe:
function appendToList(item) {
var list = localStorage["myKey"];
if (list) {
list += "," + item;
}
else {
list = item;
}
localStorage["myKey"] = list;
}
Between the time that the localStorage item is 'got' and 'set', another tab could have modified the value. It's generally unlikely, but possible - you'd need to judge for yourself the likelihood and risk associated with any contention in your particular circumstances.
See the following articles for a more detail:
Wait, Don't Touch That: Mutual Exclusion Locks & JavaScript - Medium Engineering
JavaScript concurrency and locking the HTML5 localStorage - Benjamin Dumke-von der Eh, Stackoverflow
As #william points out,
you may need a mutex if your code does something where it expects a
value not to change between when the asynchronous event was fired and
when the callback was called.
This can be generalised further - if your code does something where it expects exclusive control of a resource until an asynchronous request resolves, you may need a mutex.
A simple example is where you have a button that fires an ajax call to create a record in the back end. You might need a bit of code to protect you from trigger happy users clicking away and thereby creating multiple records. there are a number of approaches to this problem (e.g. disable the button, enable on ajax success). You could also use a simple lock:
var save_lock = false;
$('#save_button').click(function(){
if(!save_lock){
//lock
save_lock=true;
$.ajax({
success:function()
//unlock
save_lock = false;
}
});
}
}
I'm not sure if that's the best approach and I would be interested to see how others handle mutual exclusion in javascript, but as far as i'm aware that's a simple mutex and it is handy.
JavaScript is single threaded... though Chrome may be a new beast (I think it is also single threaded, but each tab has it's own JavaScript thread... I haven't looked into it in detail, so don't quote me there).
However, one thing you DO need to worry about is how your JavaScript will handle multiple ajax requests coming back in not the same order you send them. So, all you really need to worry about is make sure your ajax calls are handled in a way that they won't step on eachother's feet if the results come back in a different order than you sent them.
This goes for timeouts too...
When JavaScript grows multithreading, then maybe worry about mutexes and the like....
JavaScript, the language, can be as multithreaded as you want, but browser embeddings of the javascript engine only runs one callback (onload, onfocus, <script>, etc...) at a time (per tab, presumably). William's suggestion of using a Mutex for changes between registering and receiving a callback should not be taken too literally because of this, as you wouldn't want to block in the intervening callback since the callback that will unlock it will be blocked behind the current callback! (Wow, English sucks for talking about threading.) In this case, you probably want to do something along the lines of redispatching the current event if a flag is set, either literally or with the likes of setTimeout().
If you are using a different embedding of JS, and that executes multiple threads at once, it can get a bit more dicey, but due to the way JS can use callbacks so easily and locks objects on property access explicit locking is not nearly as necessary. However, I would be surprised if an embedding designed for general code (eg, game scripting) that used multi threading didn't also give some explicit locking primitives as well.
Sorry for the wall of text!
Events are signaled, but JavaScript execution is still single-threaded.
My understanding is that when event is signaled the engine stops what it is executing at the moment to run event handler. After the handler is finished, script execution is resumed. If event handler changed some shared variables then resumed code will see these changes appearing "out of the blue".
If you want to "protect" shared data, simple boolean flag should be sufficient.