Is JavaScript multithreaded? - javascript

Here's my issue - I need to dynamically download several scripts using jQuery.getScript() and execute certain JavaScript code after all the scripts were loaded, so my plan was to do something like this:
function GetScripts(scripts, callback)
{
var len = scripts.length
for (var i in scripts)
{
jQuery.getScript(scripts[i], function()
{
len --;
// executing callback function if this is the last script that loaded
if (len == 0)
callback()
})
}
}
This will only work reliably if we assume that script.onload events for each script fire and execute sequentially and synchronously, so there would never be a situation when two or more of the event handlers would pass check for (len == 0) and execute callback method.
So my question - is that assumption correct and if not, what's the way to achieve what I am trying to do?

No, JavaScript is not multi-threaded. It is event driven and your assumption of the events firing sequentially (assuming they load sequentially) is what you will see. Your current implementation appears correct. I believe jQuery's .getScript() injects a new <script> tag, which should also force them to load in the correct order.

Currently JavaScript is not multithreaded, but the things will change in near future. There is a new thing in HTML5 called Worker. It allows you to do some job in background.
But it's currently is not supported by all browsers.

The JavaScript (ECMAScript) specification does not define any threading or synchronization mechanisms.
Moreover, the JavaScript engines in our browsers are deliberately single-threaded, in part because allowing more than one UI thread to operate concurrently would open an enormous can of worms. So your assumption and implementation are correct.
As a sidenote, another commenter alluded to the fact that any JavaScriptengine vendor could add threading and synchronization features, or a vendor could enable users to implement those features themselves, as described in this article: Multi-threaded JavaScript?

JavaScript is absolutely not multithreaded - you have a guarantee that any handler you use will not be interrupted by another event. Any other events, like mouse clicks, XMLHttpRequest returns, and timers will queue up while your code is executing, and run one after another.

No, all the browsers give you only one thread for JavaScript.

To be clear, the browser JS implementation is not multithreaded.
The language, JS, can be multi-threaded.
The question does not apply here however.
What applies is that getScript() is asynchronous (returns immediately and get's queued), however, the browser will execute DOM attached <script> content sequentially so your dependent JS code will see them loaded sequentially. This is a browser feature and not dependent on the JS threading or the getScript() call.
If getScript() retrieved scripts with xmlHTTPRequest, setTimeout(), websockets or any other async call then your scripts would not be guaranteed to execute in order. However, your callback would still get called after all scripts execute since the execution context of your 'len' variable is in a closure which persists it's context through asynchronous invocations of your function.

JS in general is single threaded. However HTML5 Web workers introduce multi-threading. Read more at http://www.html5rocks.com/en/tutorials/workers/basics/

Thought it might be interesting to try this out with a "forced", delayed script delivery ...
added two available scripts from
google
added delayjs.php as the 2nd
array element. delayjs.php sleeps
for 5 seconds before delivering an empty js
object.
added a callback that
"verifies" the existence of the
expected objects from the script
files.
added a few js commands that
are executed on the line after the
GetScripts() call, to "test" sequential js commands.
The result with the script load is as expected; the callback is triggered only after the last script has loaded. What surprised me was that the js commands that followed the GetScripts() call triggered without the need to wait for the last script to load. I was under the impression that no js commands would be executed while the browser was waiting on a js script to load ...
var scripts = [];
scripts.push('http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js');
scripts.push('http://localhost/delayjs.php');
scripts.push('http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js');
function logem() {
console.log(typeof Prototype);
console.log(typeof Scriptaculous);
console.log(typeof delayedjs);
}
GetScripts( scripts, logem );
console.log('Try to do something before GetScripts finishes.\n');
$('#testdiv').text('test content');
<?php
sleep(5);
echo 'var delayedjs = {};';

You can probably get some kind of multithreadedness if you create a number of frames in an HTML document, and run a script in each of them, each calling a function in the main frame that should make sense of the results of those functions.

Related

When does the browser's event loop start?

I'm using a framework which features auto-connecting to server on page load. I can disable it by passing options arguments, but the line that confuses me is this:
You can prevent this initial socket from connecting automatically by disabling io.sails.autoConnect before the first cycle of the event loop elapses.
My questions are:
When does the first cycle of the event loop elapses?
Is this behaviour the same across ALL modern (IE9+) browsers?
I have a bunch of scripts (in <body>) loading between the lib and my entry file. Does this affect when the first cycle elapses? EDIT: Yes, it does.
How can I ensure my code runs before the first cycle elapses?
Is this kind of implementation of auto-connect considered good practice?
The documentation for the source file is a little more explicit; it says "This can be disabled or configured by setting io.socket.options within the first cycle of the event loop."
Basically what's happening is that there exists within the library a setTimeout(fn, 0) call, which is idiomatic for starting a parallel process. However, in the JS standards it's explicitly stated that JS is single-threaded: in other words, even though setTimeout and setInterval are asynchronous they are not actually parallel in the sense that any of their code will be executing simultaneously with any other code. So they wait until the current function is over before they execute. This queueing mechanism is known as the JavaScript event loop.
I believe that what you are asked to do by the script author is to modify the source to include the relevant change, perhaps at the bottom of the file for your convenience.
It is also likely that a similar effect will be achieved by putting a <script> tag underneath the one that loads the given JS. This has not been explicitly standardized by HTML 4, but may be implicitly standardized in the new HTML 5 spec (it's a complicated interaction between different parts of the specs).
In terms of HTML5, it looks like the current specs say that there is a afterscriptexecute event and a load event which occur immediately after any remote script is loaded (or, if it's an inline script, the load event is scheduled as a task -- I am not sure when those occur). So you might be able to guarantee it without modifying the script by instead doing:
<script>
function do_not_autoload() { /* ... */ }
</script>
<script onload="do_not_autoload()" src="./path/to/sails.io.js"></script>
but I'm not sure what the compatibility table for script#onload is going to look like.
I made you a jsfiddle which can be used to grab a 'fingerprint' for different browsers to get an idea of what evaluation orders are out there in the wild. The * is the document.body.onload event. On my system it produces:
Firefox 32.0.3 : cafdbe*
Chrome 37.0.2062 : cafd*be
IE 11.0.9600 : cafd*be
In other words,

$(window).load fires too quickly in IE with asynchronous js libs

I have some serious problem with getting asynchronously some js libs and executing them in $(window).load in IE
all works in other browsers of course
so the problem is, that I'm doing something like
<script type="text/javascript">
var scr1 = document.createElement('script');
scr1.type = 'text/javascript';
scr1.src = 'some_lib.js';
$('BODY').prepend(scr1);
</script>
Just before </body> and use $(window).load method in html above it to operate on some plugins in some_lib.js, but it all happens to fast in IE, probable because of that asynchronous lib including, and I get an error, that method is not available for the element.
Is there any chance of maybe modyfying $(window).load method so I still could use it in the same way for every browser ?
Any code that you have in the window.load() call must be placed in a function (called onLoad in this example).
Every time you have a script that you dynamically load, increment a counter. Also include something to decrement that counter...
src1.onload = function() { counter--; onLoad(); }
Then in 'onLoad' have the first line...
if (counter > 0) return;
That means that onLoad will fire at window.load and after every script is loaded, but will only execute when it's all loaded.
It's scrappy, but it will solve your problem.
You haven't really described the reason you need to load these libraries asynchronously. Third party libraries often have "on script load" functionality that you can define before the script is loaded. If you need to load multiple libraries before you can execute your code, you may have to either 1. fire up some code every time a library is loaded to test to see if all libraries required are loaded and then fire off you code 2. for every library, create a jQuery promise/deferred to get resolved when that library is loaded and use $.when(promises).done(function/code) to test and run the code whenever a particular set is loaded, or 3. rewrite to use RequireJS. If these libraries are YOUR code, well, you may have to add start up code to your libraries anyway; It might be a good time to learn RequireJS.
I wish I could recommend further, but learning the basics behind RequireJS has always been on my todo list, but it hasn't been done; I just know of people here successfully using it. If that seems like too much trouble, I'd consider some variant of option 2. If you don't know what jQuery would be used eh... you may be stuck with option 1 or 3.
Edit:
Of course, that's not to say that jQuery has got the only promise library, I just often recommend using promises in some form for these kind of things..
Archer's technique looks interesting, I just don't know how reliable it is (it might be quite reliable, I just would like to see proof/documentation). You could combine that with option 2 also, quite well, if you want to short-cut execution for some things while leaving others to be dealt asynchronously and if those script onload methods really work as expected.

Detect if any JavaScript function is running

I know it may sound very strange, but I need to know if there is any active/running javascript in the page.
I am in situation in which I have to run my javascript/jquery code after everything on the page is rendered and all other scripts have finished.
Is it possible to detect this?
EDIT:
Thank you all for the answers. Unfortunately, I was not able to find a solution, because I have no full control of what is going on the page.
Even, I was able to put my javascript in the end of the page, I think it will not be solution again. The reason is that when the page is rendering a function is triggered, it calls other functions and they calls other and so on. As a result, some of the data is incorrect and that's why i need to run my code to correct it.
I use setTimeout with 2 seconds to ensure that my code will be executed last, but this is ugly...
So, thank you all, but this is more problem with the system, not the js.
JavaScript on web browsers is single-threaded (barring the use of web workers), so if your JavaScript code is running, by definition no other JavaScript code is running.*
To try to ensure that your script occurs after all other JavaScript on the page has been downloaded and evaluated and after all rendering has occurred, some suggestions:
Put the script tag for your code at the very end of the file.
Use the defer and async attributes on the tag (they'll be ignored by browsers that don't support them, but the goal is to make yours the last as much as we can).
Hook the window load event via a DOM2 style hookup (e.g., addEventListener on browsers with standards support, or attachEvent on older IE versions).
In the load event, schedule your code to run after a setTimeout with a delay of 0ms (it won't really be zero, it'll be slightly longer).
So, the script tag:
<script async defer src="yourfile.js"></script>
...and yourfile.js:
(function() {
if (window.addEventListener) {
window.addEventListener("load", loadHandler, false);
}
else if (window.attachEvent) {
window.attachEvent("onload", loadHandler);
}
else {
window.onload = loadHandler; // Or you may want to leave this off and just not support REALLY old browsers
}
function loadHandler() {
setTimeout(doMyStuff, 0);
}
function doMyStuff() {
// Your stuff here. All images in the original markup are guaranteed
// to have been loaded (or failed) by the `load` event, and you know
// that other handlers for the `load` event have now been fired since
// we yielded back from our `load` handler
}
})();
That doesn't mean that other code won't have scheduled itself to run later (via setTimeout, for instance, just like we did above but with a longer timeout), though.
So there are some things you can do to try to be last, but I don't believe there's any way to actually guarantee it without having full control of the page and the scripts running on it (I take it from the question that you don't).
(* There are some edge cases where the thread can be suspended in one place and then allow other code to run in another place [for instance, when an ajax call completes while an alert message is being shown, some browsers fire the ajax handler even though another function is waiting on the alert to be dismissed], but they're edge cases and there's still only one thing actively being done at a time.)
There is no definitive way to do this because you can't really know what the latest is that other scripts have scheduled themselves to run. You will have to decide what you want to target.
You can try to run your script after anything else that may be running when the DOM is loaded.
You can try to run your script after anything else that may be running when the page is fully loaded (including images).
There is no reliable, cross-browser way to know which of these events, the scripts in the page are using.
In either case, you hook the appropriate event and then use a setTimeout() to try to run your script after anything else that is watching those events.
So, for example, if you decided to wait until the whole page (including images) was loaded and wanted to try to make your script run after anything else that was waiting for the same event, you would do something like this:
window.addEventListener("load", function() {
setTimeout(function() {
// put your code here
}, 1);
}, false);
You would have to use attachEvent() for older versions of IE.
When using this method, you don't have to worry about where your scripts are loaded in the page relative to other scripts in the page since this schedules your script to run at a particular time after a particular event.
A way to know when multiple functions have all finished executing
This can be useful if you have to wait multiple API calls or initialisation functions
let processRemining = 0;
async function f1() {
processRemining++
await myAsyncFunction()
processFinished()
}
async function f2() {
processRemining++
await myAsyncFunction2()
processFinished()
}
function processFinished() {
processRemining--
setTimeout(() => { // this is not needed is all the functions are async
if (processRemining === 0) {
// Code to execute when all the functions have finished executing
}
}, 1)
}
f1()
f2()
I often couple it with a freezeClic function to prevent users to interact with the page when there is a script that is still waiting an ajax / async response (and optionnaly display a preloader icon or screen).

Dynamic script addition should be ordered?

I'm adding some <script> tags dynamically to the head element after page load. I understand the scripts are loaded asynchronously, but can I expect them to be parsed in the order they are added?
I'm seeing the expected behaviour in Firefox, but not in Safari or Chrome. Looking at the document in Chrome developer tools and Firebug, both show the following -
<html>
<head>
...
<script type="text/javascript" src="A.js"></script>
<script type="text/javascript" src="B.js"></script>
</head>
...
</html>
However looking at the resource loading view, chrome seems to parse whichever is returned first from the server, while firebug always loads them in the order the script tags were added, even when B is returned first from the server.
Should I expect Chrome/Safari to parse the files in the specified order? Using Chrome 5.0.375.29 beta on OS X 10.6.3
EDIT (10/5/10): When I say parse, I mean execute - can see many benefits of aggressive parsing - thx rikh
EDIT (11/5/10): Ok so I put together a test along the lines of that by juandopazo below. However I have added a combination of things, including
Adding the script element to the head directly with javascript. (Tests A -> D)
Adding the script element to the head using jquery's append() method. (Tests E -> H)
'Loading' the script with jquery's getScript() method. (Tests I -> L)
I also tried all combination of the 'async' and 'defer' attributes on the script tags.
You can access the test here - http://dyn-script-load.appspot.com/, and view source to see how it works. The loaded scripts simply call the update() function.
The first thing to note, is that only the 1st and 3rd methods above operate in parallel - the 2nd executes requests sequentially. You can see a graph of this here -
Image 1 - Graph of Request Lifecycle
Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png
It's also interesting that the jquery append() approach also blocks getScript() calls - you can see that none of them execute until all of the append() calls are complete, and then they all run in parallel. Final note on this is that the jQuery append() method apparently removes the script tags from the document head once they have executed. Only the first method leaves the script tags in the document.
Chrome Results
The results are that Chrome always executes the first script to return, regardless of the test. This means all the test 'fail', except the jQuery append() method.
Image 2 - Chrome 5.0.375.29 beta Results
Chrome Results http://dyn-script-load.appspot.com/images/chromeDynScript.png
Firefox Results
On firefox, however, it appears that if the first method is used, and async is false (i.e. not set), then the scripts will reliably execute in order.
Image 3 - FF 3.6.3 Results
FF Results http://dyn-script-load.appspot.com/images/ffDynScript.png
Note that Safari seems to give varied results in the same manner as Chrome, which makes sense.
Also, I only have a 500ms delay on the slow script, just to keep the start->finish time down. You may have to refresh a couple of times to see Chrome and Safari fail on everything.
It seems to me that without a method for doing this, we are not taking advantage of the ability to retrieve data in parallel, and there is no reason why we shouldn't (as firefox shows).
Sorry for answering my own question, but its been a while and we did come up with a solution. What we came up with was to load the javascript concurrently as text contained in a json object, and then used eval() once they were all loaded to execute them in the correct order. Concurrent load plus ordered execution. Depending on your use case you may not need the json. Roughly, here is some code that shows what we did -
// 'requests' is an array of url's to javascript resources
var loadCounter = requests.length;
var results = {};
for(var i = 0; i < requests.length; i++) {
$.getJSON(requests[i], function(result) {
results[result.id] = result;
...
if(--loadCounter == 0) finish();
});
}
function finish() {
// This is not ordered - modify the algorithm to reflect the order you want
for(var resultId in results) eval(results[resultId].jsString);
}
As I understand it, they are meant to be executed in the order they appear in the document. Some browser might be able to perform some parsing out of order, but they would still have to be executed in the correct order.
No, you cannot expect that all browsers will defer execution of both scripts until both are loaded (**especially when you are adding them dynamically).
If you want to execute code in B.js only after A.js is loaded then your best bet is to add an onload callback to A.js that sets a variable and another one to B.js that checks to see if that variable has been set, then it executes the necessary function in B.js if it has (and if A.js has not loaded, it starts a timer that periodically checks until it has loaded).
The download order and the execution order is not the same thing. In your page, even if B.js is downloaded first, the browser's engine will wait for A.js to continue processing the page.
The scripts are definitely processed, not only in the order they appeared in the document, but also at the place they appeared.
Imagine if it wouldn't be like that, there would be many errors if your little script that uses jQuery is downloaded and processed before the jQuery library.
Also, when you do a "document.write" in a js file, it appears where the script has been declared. You can't access DOM objects that are appearing after the script declaration neither.
This is why there are recommendations to put scripts at the very bottom of the page, to prevent their execution too soon and decrease the "perceived load time" of the page, because the browser's rendering engine is stopped as soon as a script is processed.
Mike
EDIT: if they are added dynamically with javascript, I think they are processed in the order they were added in time.
You could load b.js from a.js to be 100% sure ... although I'd like the definitive answer to this question myself, especially with sync ajax loading of scripts.
I was investigating this while working on a little library that loads modules dynamically like YUI 3. I created a little test here that loads two scripts that just insert content into divs. One is a common JS file and the other is a PHP file that waits 3 seconds to execute.
http://www.juandopazo.com.ar/tests/asyn-script-test.html
As you can see, scripts are executed when they finish loading, and not in the order in which you append them to the DOM, in every browser.

jQuery profiling - measure complete onReady runtime

I'd like to measure how long it takes to run the whole $().ready() scope in each of page.
For profiling specific functions I just set a new Date() variable at the beginning of the relevant part and then check how long it takes to get to the end of the relevant part.
The problem with measuring the whole $().ready scope is that it can sometimes run some of the code asynchronously and then I can not wait for it all to finish and see how long it has taken.
Is there any event which is fired once the page has completely finished running all $().ready code?
EDIT: Using Firebug or other client debuggers are not an option since I also need to collect this profiling information from website users for monitoring and graphing our web site's page load speeds
Thanks!
There will be no event fired because its virtually impossible for ready() to know when any asynchronous functions are done processing. Thus, you'll need to bake this functionality in yourself; you could use jQuery's custom events, or perhaps set a function to run on setInterval() that can introspect the environment and deduce whether or not everything else is done.
Swap out the jQuery ready function with a function that does your start and finish tracking, and calls the original method.
jQuery.ready = (function() {
var original = jQuery.ready;
return function() {
alert('starting profiler');
original();
alert('ending profiler');
};
})();
$(function() {
alert('this message will appear between the profiler messages above...');
});
Have you tried using Profiler in Firebug?

Categories