What part of the following function make it asynchronous? - javascript

I'm learning javaScript and just came on the topic of promises , async await , fetch etc.
While reading a tutorial online , It described the following code as asynchronous
function loadScript(src) {
let script = document.createElement('script');
script.src = src;
document.head.append(script);
}
I have learned that javascript hands over all the asynchronous work to the browser , like http request as they take time and might block the flow in javascript.
Please point out to me how the above code is asynchronous?
Which part of it is asynchronous? Is it because we are using document object?
are all methods in document object asynchronous and handled by the browser?
or is it something else?
here is the link to the tutorial, sorry if I misunderstood something.https://javascript.info/callbacks

It's asynchronous because you're fetching the script code from the server, using the src URL. That has to send a network request, and the code won't be inserted into the DOM and executed until the server responds.
Modifying the DOM itself is synchronous, but a number of elements can cause network requests to be sent and wait. Examples are <script>, <img>, and <iframe>.

The script tag itself needs to load the url so this is the part that is asynchronous. Scriptloads are handled by the Browser.

If you're referring to the fact that dynamically created script elements behave as though they have their async attribute set, that's outlined in the spec:
A script element has a flag indicating whether the element will be "non-blocking". Initially, script elements must have this flag set. It is unset by the HTML parser and the XML parser on script elements they insert. In addition, whenever a script element whose "non-blocking" flag is set has an async content attribute added, the element's "non-blocking" flag must be unset.
...but even if the script element doesn't have async set, the download of the source code is still going to happen asynchronously; async simply says "don't block further HTML parsing or JavaScript execution while waiting for this to download." The code that injects the script will still finish running, but any subsequent script elements on the page will wait for blocking scripts to download.

Related

Does the async attribute block the page content?

My question is related to async attribute in script tag.
In the https://javascript.info/script-async-defer link, I can see "The page content shows up immediately: async doesn’t block it."
But as far I understand, if we use the async attribute, fetching the script will happen in parallel but executing the script will block HTML parsing. So obviously page content will be blocked by the async attribute.
Can someone clarify what goes wrong in my understanding? will async block the page content?
The async attribute is used to indicate to the browser that the script file can be executed asynchronously. The HTML parser does not need to pause at the point it reaches the script tag to fetch and execute, the execution can happen whenever the script becomes ready after being fetched in parallel with the document parsing.
This attribute is only available for externally located script files. When an external script has this attribute, the file can be downloaded while the HTML document is still parsing. Once it has been downloaded, the parsing is paused for the script to be executed.
summary: async stops the parsing while script is being executed but after script execution as you can see in picture, still load parsing

When can we use async?

Async script loading is what i'm learning now. I have a question about async attr in script tag - <script async src="...">.
here is some info, http://www.w3schools.com/tags/att_script_async.asp and my question is about this - When present, it specifies that the script will be executed asynchronously as soon as it is available. line.
Question:
If i have 2 scripts:
<script async src="url1.js"><script> // 200kb
<script async src="url2.js"><script> // 2kb
and the second script must be executed AFTER first (it uses some Objects or functions from it) - will it be so after page load? will first script execute first after loading, and then - the second, or not?
From bold string above - I understand it so, that than faster the script was loaded - the faster it will be executed, and in our example we will have errors, while first script wasn't loaded and executed yet, but second is already trying to get it. (and when we can use async script loading? only when our scripts are not independent of each other?)
p.s. is lazy loading script the only way to get the correct script execution order in this case - to prevent errors?
Without the async attribute, the browser will stop processing the page and first download the referenced script; once the script is downloaded and executed it will continue processing the next tag on the page. This has two consequences:
All scripts are guaranteed to load in the order they're included in the HTML, and dependencies are guaranteed to resolve correctly.
The page loading is noticeably delayed, if those scripts are included early. Synchronous scripts should always be included at the end of the page to not leave the visitor waiting needlessly.
If you set the async attribute, the browser will continue loading the page without stopping to process the script tag, and will load the script sometime later. When exactly the script is loaded is undefined and you cannot depend on any particular order of execution. If you have dependencies between two scripts, you cannot load them asynchronously, because then it's down to pure luck whether one will load before the other.
As such, async loading is only useful for scripts which have no other dependencies. Or: you hook your scripts to the window.onload event and avoid making any cross references before then; the event will be fired after all scripts have loaded, including async scripts.
If url2.js depends on url1.js you cannot use async loading for script files you must use synchronous (eager loading) to ensure that url1.js is loaded and executed before url2.js.
Using async two cases can occur:
url1.js loads and executes then url2.js loads and executes. This is okay as url1 will be ready for url2.
url2.js loads and executes then url1.js loads and executes. This will fail as url2 depends on url1 which is not ready at the time url2 is.
Using non-async loading only one case can occur, which is url1.js loading and executing before url2.js loads and executes which is what you need if they depend on each other.
In async loading you can't control when they are executed, they execute as soon as they are loaded.
We had a similar Question asked earlier.
Script Tag - async & defer
And about the order of execution, JavaScript execution happens in the order they're placed in HTML. If your page relies on the JavaScript for certain events and if the JS Methods are loaded before your Page, then they'll result in the JS Error.
I would suggest you to use the CallBack functions where possible to avoid the above errors. Here is a good place to start to learn about the CallBack functions and how you can implement them.

Android WebView: is there a way, in javascript, to load another javascript file and preserve filename/line number information for stack traces?

I've got a WebView. It's got some javascript. I need to dynamically and synchronously load more javascript stored in the assets folder.
eval() works just fine when I pull in the code from the asset by hand and pass it as a string.
The problem is that stack traces aren't useful for code that was pulled in with a string eval. You just get "eval at (file:///android_asset/..."
Is there another way to dynamically pull in javascript code, from javascript, that would make stack traces useful?
(FYI, I'm just using WebView as a javascript engine so I can use lots of our existing cross-platform javascript. It's not displaying any sort of useful HTML.)
Edit:
You can add this:
/# sourceURL=snarkloading.js
To the string that gets evaled, and you'll get snarkloading.js as the name of the file.
You can load scripts like this...
var script = document.createElement('script');
script.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js");
script.onload = function () {
// Do your thing when script is loaded
alert('script loaded');
};
document.documentElement.appendChild(script);
Write your code in the onload event handler. This is when the code is actually downloaded and available.
Update
There is a way to download scripts synchronously. I remember using the jQuery Ajax function for this with the following option.
async (Boolean)
Default: true
By default, all requests are sent
asynchronously (i.e. this is set to true by default). If you need
synchronous requests, set this option to false. Cross-domain requests
and dataType: "jsonp" requests do not support synchronous operation.
Note that synchronous requests may temporarily lock the browser,
disabling any actions while the request is active. As of jQuery 1.8,
the use of async: false is deprecated.
You can read more about this on the jQuery API documentation for Ajax. The documentation states that it is deprecated in as jQuery 1.8. But if you can get your hands on an older version you can use that one or figure out how they did it.

Does JSONP make an asynchronous call?

I am new to jsonp and I understand that JSONP is a technique which creates a dynamic
<script src="..."> tag, that wraps the returned JavaScript (or JSON object) with a callback function.
But if I am not mistaken, src attribute in a script tag will hold back all further executions until the script loads, so how can it be asynchronous call?
Actually, as you can read up on here and here dynamically created <script src=".."> elements after the DOM has finished loaded will NOT be blocking and by that they will be asynchrounus.. at least in the order they are created.
qutoted from http://calendar.perfplanet.com/2010/the-truth-about-non-blocking-javascript/
When inserting a script dynamically, the non-blocking download begins immediately. The script executes as soon as it is downloaded completely. In most browsers, the order of execution is not guaranteed, though Firefox < 4 and Opera will execute the scripts in the order in which they were inserted. This general approach is supported in all major browsers.
I think your question has two parts.
First, JSONP is essentially not about dynamic script tags, rather dynamic script tags are a technique used hand in hand with JSONP.
JSONP is a method which allows site to load content from different domains than the ORIGIN, exploiting the browser's tolerance towards SCRIPT tags with src pointing to external domains. (You should know this by going through the links given in other answers).
Dynamic SCRIPT tags on the other hand provides an Asynchronous nature to any script be it JSONP or otherwise.
Point is, whenever a browser hits a SCRIPT tag on a document, it stops most other activities (rendering DOM specially) until that script is download. This affects users experience on how responsive the site is. Effect of this is even worse if the script is not directly contributing to the primary content of the site (such as Google Ads, Tweets, or Facebook Timeline (Asuming you are not Mark Z. :P), etc)
To avoid this problem, you can inject dynamic SCRIPT tags to the page once it has fully loaded on the browser (i.e ready/loaded event). Then the browser will silently load the new script, but user has the full page (almost) rendered for him giving impression of quick loading. In that sense dynamic scripts can be asynchronous to page loading.
However, in practice most of scripts used in this way are JSONP scripts residing on different domains, although it's not a requirement.
Hope this makes sense.
For TRUE async script loading you should look into HTML5 sync attribute:
The call is asynchronous, yes. Maybe you are confusing the behaviour of a script tag when the page is loading and when the page is already loaded.
As the page is being loaded by the browser, all HTML tags with resources (image tags, link tags, etc...) have their resources downloaded assynchronously and don't interrupt the browser rendering task. This has the improvement of optimizing the performance of the page rendering.
The only tag which doesn't follow this rule is the script tag. Because the browser has to ensure the order of the scripts, it will not load them in parallel. Additionally, the browser has to count with dynamic alterations on the HTML document made from the script, using document.write, and for this reason it will evaluate the script as soon as it is downloaded. So, this is the default behaviour from the browsers concerning script tags with src file: they will block the rendering of the page, be downloaded in sequence and will be evaluated as soon as they have been loaded. There are techniques to avoid this, like placing the scripts at the bottom of your document (scripts will only be downloaded and evaluated after the document has been rendered) or using the new HTML5 script tag attributes "async" and "defer": http://blogs.microsoft.co.il/blogs/gilf/archive/2011/12/29/the-async-and-defer-script-attributes-in-html5.aspx .
Going back to JSONP: yes, it is asynchronous in the way that it is not blocking any further browser behaviour (page is already rendered). This is the asynchronicity regular AJAX calls provide.
JSONp includes don't really work like AJAX calls since they're a bit of a hack. If I were pressed to put them in either box I'd go with "asynchronous".
I guess the most important trait is that the 'return value' will show up in another event.
You can't write:
var return_value = do_jsonp("my function");
You have to write this instead: (or use some sort of promise library)
do_jsonp("my function", function (return_value) {});
So, when the script in the JSONp resource actually gets executed is not relevant. All that is relevant is that it happens in a different event.
This related question should shed some light on your question.
Script nodes added dynamically using javascript are executed asynchronously and they won't block execution of other scripts.
you are kind of misinterpreting the word "asynchronous". the javascript excecution is asynchronous, which means the every line of javascript-code which comes after you inject your script-tag is executed.
example:
var yourCB = function(result) { ... }
// i use the script injection from neiker here (without the async = true, to illustrate that this has nothing to do with the asynchronous nature JSONP
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.src = 'http://domain/api/...?callback=yourCB';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
// everything after the script insertion is excecuted, even if your jsonp-callback hasnt been called. as soon as your script-request has finished yourCB is called.
alert('THIS IS ALERTED EVEN IF yourCB HASNT BEEN CALLED');
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = 'http://domain/api/...?callback=something';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
Anyway, can't you use jQuery? If not, try this: https://github.com/ded/reqwest

Proper way to execute JavaScript returned via AJAX (no jQuery)

Say I get a response to a request for an AJAX load of data with a mix of JavaScript and HTML, e.g.:
<script>window.alert('Hello World!');</script>
<p>This is a paragraph. Lorem ipsum dolor sit amet...</p>
If I just place that response into a div or other container, the script doesn't get executed automatically. I know this can be done via the eval() function (as noted in the example below), but eval is evil, so how can I do this properly? Note: I am not using jQuery.
The following is an example of the AJAX loader:
function Load(id,url){
var ajax=new XMLHttpRequest();
ajax.onreadystatechange=function(){
if(ajax.readyState!=4)return;
var obj=document.getElementById(id);
if(!obj)return;
obj.innerHTML=ajax.responseText;
// load any scripts
var s=obj.getElementsByTagName('script');
for(var i=0;i<s.length;++i)window.eval(s[i].innerHTML); // <-- bad
}
ajax.open("GET",url,true);
ajax.send(null);
}
Please note that you're taking input from the user and running it in the context of a script on your site. So the script can do anything that JavaScript running on your browser/domain would have the ability to do (including cookie stealing, XSS, drive-by malware, etc.).
The only thing you can realistically do to mitigate the risks is to not eval() user-provided content. I'd suggest to consider the following alternatives:
Use iframe as an environment to run user's script:
http://dean.edwards.name/weblog/2006/11/sandbox/
Use Caja. It allows websites to safely embed DHTML web applications from third parties, and enables rich interaction between the embedding page and the embedded applications. It uses an object-capability security model to allow for a wide range of flexible security policies.
http://code.google.com/p/google-caja/
eval isn't particularly evil in this scenario, it's not a lot different than, say dynamically adding a script tag which pulls down a .js file and runs it. That said, there are other options, for instance you can dynamically create a script tag, create a text node with the contents of the script tag you pulled down, and add that to the document. Unlike the innerHTML technique, that will actually run the contents. The only advantage over eval, really, is that you might get a more meaningful stack trace etc if it crashes or has a syntax error.
var newScriptTag = document.createElement('script');
newScriptTag.appendChild(document.createTextNode(
origScriptTag.innerHTML)
document.body.appendChild(newScriptTag);
I solved this today by putting my JavaScript at the bottom of the response HTML.
I had an AJAX request that returned a bunch of HTML that was displayed in an overlay. I needed to attach a click event to a button in the returned response HTML/overlay. On a normal page, I would wrap my JavaScript in a "window.onload" or "$(document).ready" so that it would attach the event handler to the DOM object after the DOM for the new overlay had been rendered, but because this was an AJAX response and not a new page load, that event never happened, the browser never executed my JavaScript, my event handler never got attached to the DOM element, and my new piece of functionality didn't work. Again, I solved my "executing JavaScript in an AJAX response problem" by not using "$(document).ready" in the head of the document, but by placing my JavaScript at the end of the document and having it run after the HTML/DOM had been rendered.

Categories

Resources