Onload can fire early when using jsp dynamic includes? - javascript

When a jsp page includes jsp dynamic includes...
<jsp:include page=”filename.jsp” />
...is it possible that the document onload event (or prototype's dom:loaded event) could get fired too early? (i.e. before the included filename.jsp has fully loaded)
The reason I suspect this may be the case is that the included file is compiled separately and only included by directive at runtime. The parent jsp might assume that loading of the directive itself is sufficient to consider the DOM is loaded - the includes page is loaded asynchronously and its loading is might not be monitored by the document.
Is this a valid concern?
Thanks in advance

This is included serverside, not clientside. It's certainly not asynchronously. The client receives one response. Rightclick page and view source. It's all plain HTML.
If you have problems with onload, it lies somewhere else. Verify/validate the generated HTML output.

Related

How does TurboLinks display response HTML?

I am studying the basic internal functionality of the JavaScript TurboLinks framework at the moment. From what I understand, onclick events are assigned to all anchor tags to be able to prevent the default action (full page reload) and load the link content via AJAX instead. Please correct me if I am wrong here.
When the AJAX callback receives the whole HTML document as a string, how can it be rendered without (re)loading script and style tags?
Scripts and styles will only be (re)loaded and evaluated when they are inserted into a page. When the HTML is received via AJAX, Turbolinks creates a new HTML document behind-the-scenes, and sets its content to the HTML response. As this is not yet rendered/inserted, the browser does not download/evaluate any scripts or styles. The <head> of the new document can now be compared to the current one and additional assets can be added as necessary.
In terms of the specific Turbolinks components:
Visits create Snapshots from the AJAX response (see Visit#loadResponse)
Snapshots create HTML elements behind-the-scenes (see Snapshot#fromHTMLString
SnapshotRenderers handle merging the <head> and replacing the <body> (SnapshotRenderer#mergeHead and SnapshotRenderer#replaceBody)

Dynamically added script tag doesn't execute when moved with jQuery

I'm using jQuery 2.1.3 on an Asp.net MVC site that renders partial views to certain site areas.
A partial view can contain a script block that manipulates the area DOM. Partial views can also contain other partial views, and I can thus end up with several script tags.
This is usually not a problem. For simplicity I have made this example that alerts both 1 and 2:
$("body").html('<div id="target"><script>alert("dynamic dom 1");<\/script></div><div id="source"><script>alert("dynamic dom 2");<\/script></div>');
But if the first script manipulates the DOM, and moves the div containing the second script tag, the entire script isn't executed, and I only get alert 1:
$("body").html('<div id="target"><script>alert("dynamic dom 1");$("#target").append($("#source"));<\/script></div><div id="source"><script>alert("dynamic dom 2");<\/script></div>');
I'm not getting any JS errors that could stop execution!
I'm using jQuery.append(), that should and in fact does move the div element.
I have tried using ready() handlers to ensure that the DOM is fully loaded, but with the same effect.
This only seems to be a problem with dynamically loaded HTML. It works if I include the code in a plain html file, but with a single page MVC site that's not a usable workaround.
Is this a bug in jQuery.html() or jQuery.append(), or am I using it wrong?
EDIT: I'm not having problems adding the script tag(s). I'm not quite sure how added script tags are executed, and how one added script can affect the execution of the other. This could be the source of the problem. If you know how jQuery handles this, then please elaborate.
EDIT 2: I have recently made a big jQuery update, and this code worked with older jQuery versions. In fact, this works with jQuery-1.8.3, but not with jQuery-1.9.0 (or later). In this update jQuery marks inserted scripts as executed to prevent them from being run several times.
See: http://bugs.jquery.com/ticket/11795
and: http://jquery.com/upgrade-guide/1.9/#loading-and-running-scripts-inside-html-content
I know that it is poor practice to mix JS and HTML, but with MVC partial views it helps maintainability and overview to keep the JS and HTML in the same view file.
Nevertheless, I think that jQuery somehow wrongfully marks the second script to have been executed, when in fact it has not. Can someone please explain how scripts are marked as executed?
In general
It seems that from jQuery 1.9.0, when dynamically inserting DOM elements that include script tags, jQuery first scans/parses the input DOM and tags scripts as executed. It then traverses the DOM and evaluates the scripts.
See: http://jquery.com/upgrade-guide/1.9/#loading-and-running-scripts-inside-html-content
When the script tag is moved with jquery.append(), it is already tagged as executed and thus won't be evaluated.
It is not important where in the DOM hierarchy the script tag is moved to/from. The first $.html() tags it as executed, and when moving it, the subsequent $.append() doesn't know that it in fact wasn't executed yet.
To evaluate it explicitely one can do eval($("#source script").text()), i.e.:
$("body").html('<div id="target"><script>alert("dynamic dom 1");$("#target").append($("#source"));eval($("#source script").text());</script></div><div id="source"><script>alert("dynamic dom 2");</script></div>');
For Asp.net MVC
This will help Asp.net MVC partial views where you want to keep the JS close to the DOM elements it manipulates (i.e. in the same file), e.g.:
$("body #someContainer").html('#Html.Partial("_myWidget")');
with "_myWidget.cshtml":
<div id="target">#Html.Partial("_myWidgetContent")</div>
<script>
alert("dynamic dom 1");
$("#target").append($("#source")); //or some other setup that manipulates the widget DOM
eval($("#source script").text();
</script>
and "_myWidgetContent.cshtml":
<div id="source"></div>
<script>
alert("dynamic dom 2");
//Something specific to this partial view
$("#source").click(function() { alert("clicked") });
</script>

Does JavaScript run again when the browser retrieves a cached html page?

I have a html page that doesn't change too much and I want to cache it for one week for ex.
In this html I have some JS scripts that does some ajax requests and modifies the html.
When the browser loads this page, does the JS scripts run?
10x
Yea, it does.
JavaScript is always executed on page load, cached or not.
Unless you're postponing the JS with a onload handler, of course, then it's executed after the page's loaded.
Yes, JS code runs each time the page is loaded.
As well, you can use onLoad event on body tag or jQuery event $(docuemnt).load(...).

What to use in place of $(document).ready();?

So I'm using jquery along with some plugins I wrote.
I do all the initialization in a $(document).ready(function(){}) block however this is executed when the whole DOM has been loaded and is ready to be used.
However that would take long eg. when there is a server load. Or maybe the user clicks a button that has been loaded while the rest of the page hasn't loaded yet (and thus document.ready() hasn't been executed yet) in which case it would do nothing.
So, what if I want a code to be executed right after the related part of the page has been loaded instead of waiting for the WHOLE page to be loaded?
I know placing inline code right after the html that this js operates on would do the trick but what if that code uses a library like jQuery that hasn't been loaded yet?
I know placing inline code right after the html that this js operates on would do the trick but what if that code uses a library like jQuery that hasn't been loaded yet?
That would be the only way. The HTML is parsed from top to bottom. So you can expect every script you included to be accesible after you included it.
Your page should still work without JavaScript anyway, so a user clicking a button extremely fast will just temporarily have a somewhat degraded experience.
That being said, the DOM is basically ready when the HTML document all scripts are loaded. Since you cannot execute meaningful JavaScript before the JavaScript code is loaded (duh), I'd have a close look at page performance. Sending an HTML document and 2,3 JavaScript files should not be slow.
You could also use the old-style inline event handlers, like <button onclick="registerButtonClickEvent()">. However, this would introduce a complex, potentially buggy and hardly testable layer of temporary event holding.
If your <script src="jquery-whatever.js> line precedes the first clickable element in your HTML, it is guaranteed that the jquery library will be loaded and run before the user has anything useful to click on.
Just don't add async or defer attributes to the script element.
The onload event isn't triggered from all html elements, so you're forced to wait for window load. It doesn't matter where you load jQuery since it will have to wait for document to be ready. That total time required to load jQuery plus the rest of the document will be thet same.

Browser loading strategy, <head>...<body>

I am inspecting some interesting behaviors of browser, I don't know it's in standard or not. If I put everythin inside <head></head>, the browser will only begin to render the page after all the resouces in head is retrieved.
So I am thinking that put as little as possible things into head is one of the important website optimization techniques, is it right? My question is:
If I put script/css in body or other parts of the html, how can I know that script has been loaded successfully so that I will not be calling a undefined function?
To answer shortly: You should really put the script tags at the very end of the <body> element. Style tags should be put in <head>, otherwise the document will have to be re-rendered every time a new stylesheet is loaded, so you really want them all to be loaded before the document starts rendering.
As for using javascript code that is not loaded yet. Of course you shouldn't bind any events or anything too early, and shouldn't have inline javascript in the page ideally. The solution can be to just use the window onload event to do your initialization, if you really must have inline code in the page.

Categories

Resources