Please Help.
Question: Can I dynamically load a JS file (/scripts/banner.js) and then use one of its functions -- writeBanner(document, t1, t2, t3) -- to finish writing the page?
I've read till my eyes bleed, but:
-- Every example I find assumes the reader will call a function AFTER the page is rendered, and
-- Every example assumes blocking is bad.
Unfortunately:
-- I need to call the functions in order to finish writing the page that loaded them, and
-- Blocking is not a problem. The app is deployed as an EAR file, so no JS files need thereafter be downloaded from anywhere else.
Why try to do this?
The initial window ("TAPP") loads a dozen functions from 6 JS files. All pages use them to write HTML in the page's body element that displays a consistent banner with up to 3 paramaterized title lines.
Level-1 Pages: These are opened in the initial ("TAPP") window by each other. It already has all functions loaded – works perfectly.
Level-2 pages: These are opened in pop-up windows opened by level-1 pages. They use "this.opener", i.e. "TAPP" to call those functions – works perfectly.
Now I want to be able to open Level-2 pages both
-- as pop-ups from a level-2 page, AND
-- as free standing pages.
NOTE: All level-2 pages.jsp being with this include to write the HEAD element:
<%# include file='/jsp-pages/level-2/headers/beg.jsp' %>
That way I only need to deal with scripting for all of them, in one place, at one time.
First Step: I added this code to beg.jsp:
<script language="javascript">
var SH = "";
if (this.opener && this.opener.name == "TAPP") {
SH = this.opener; // TAPP has all required functions
} else {
//Dynamically add the required <script> elements
/************************************/
// see code I tried below
/************************************/
SH = this; // "this" now has all the functions TAPP has
// alert ("Opener is NOT TAPP: " + SH);
}
// All pages can now call SH.writeBanner(document, t1,t2, t3) with their own titles
</script>
Here's the rub. When the alert () function above is uncommented BOTH tries (DOM and document.write() below) work perfectly. When it is commented out, level-2 pages opened as pop ups work perfectly BUT when opened as free standing pages do NOT write their titles. Obviously they are being rendered before the script is loaded.
My Tries to date:
-- Give up! Skip the code above. Hard-code six additional tags in "/jsp-pages/level-2/headers/beg.jsp" that will reload the functions in the six JS files every time any level-2 page is opened Either way.
Ugly, inelegant, redundant, a waste if the page is opened as a pop-up, to be avoided at all cost.
-- When TAPP is not this.opener, use DOM to load the JS files by adding script elements at the end of
<script type="text/javascript">
function dynamicload(){
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.setAttribute("src", "/scripts/banner.js");
script.async = false; // halt rendering until writeBanner() is loaded?
head.appendChild(script);
//alert ("DL Done");
}
dynamicload();
</script>
-- When TAPP is not this.opener, use document.write() to write the six scripts.
<script type="text/javascript">
document.write('<SCR'+'IPT src="/scripts/banner.js '><\/SCR'+'IPT>');
// and six more like it
</script>
So HELP!
Is it really NOT possible to use dynamically loaded functions to finish writing the page that dynamically loaded them?
glb
You can add things to the current page using dynamically loaded code. But, you cannot use document.write() to do so. You must add DOM elements directly to the page with methods like .appendChild() or .insertBefore() or set .innerHTML on an existing DOM element.
The problem with document.write() is that once the page had been loaded (and thus the document stream closed), any future calls to document.write() will clear the current page and start writing to a new, blank page which general ruins what you are trying to do.
And, when you dynamically load code, it will load AFTER the current document has finished loading.
document.write() is intended to insert content at the current location in the document stream while the document is in the process of loading which only works when the script is present in the original HTML either as a <script> tag or it can be used on a brand new document (such as the creation of a new iframe or new window).
Simple answer. You can't.
A page cannot load JS files with functions it needs to write the rest of the page.
No matter how you script to load the JS files -- add a script element with DOM, or write it in with document.write() -- the JS files end up being loaded AFTER the page is loaded when it is too late to write the page. (See discussion with nothingnecessarey.)
However, it still bothers me that if I throw an alert() in my the script, both conditional approaches work – DOM and document.write() -- i.e. I had titles! All I can think of is the alert causes the page to re-render itself and since the alert is called after the page is loaded, the JS files are loaded.
Thanks to all for their help
AFTERTHOUGHT: I dreamed that opening an empty page with an iFrame to load my level-2 might work. If so I'll return. If not ... I give up.
Related
Without inserting inline scripts, how can I check if a specific page has loaded? Usually I put an inline script that calls a function in the page's html head using window.onload, but how can this be achieved with a linked JavaScript file?
For example, suppose I have a button that opens a special page, and I need the DOM to be ready before I start any using scripts on that. Should I use two JavaScript files, linked at the bottom of each body?, then wrap everything in a function called by the onload event?
It's pretty common practice to place the script tags at the bottom of the page, just before the final body tag. This will mean that the DOM would have loaded by this point and it will be safe to execute your code. Also it means that your scripts won't be downloaded till the very end which makes for a better experience for visitors.
If you wanted to be particular about it, you could then add an event listener onto the body tag and have your code run after body loads. I'm not sure your exact use case so I don't know if this would serve your purpose better. Assuming you aren't doing anything out of the ordinary and your scripts are placed just before the final body tag this wouldn't make much of an extra difference as the majority of the DOM would have already loaded. If you did want to do this you'd use the following code.
var bodyElement = document.getElementsByTagName("BODY")[0];
bodyElement.onload = function () {
// Your loading function
}
Let A be the page with the button you click.
Let B be the the special page that opens on A's button click
I struggle to understand what you're asking exactly, but this sounds like a case of "A comes before B".
If the button on page A is clickable after that page finishes loading, then the script that runs after page B finishes loading can safely assuming that both A and B have loaded. You can write logic in B that depends on A being loaded only if you can guarantee that A loads B. What happens if B is accessed directly bypassing A?
Possible markup for B follows:
<html>
<head>
<title>Special Page</title>
</head>
<body>
<script src="test.js"></script>
</body>
</html>
The test.js file linked above:
window.onload = function(){
console.log('special page is loaded');
};
The onload event on page B may safely assume A has loaded but only if you can guarantee A always calls B.
I have no idea if you're trying to load page B into an iframe or do a page redirect from A to B or fetch B into A by way of Ajax and HTTP GET.
in my Javascript code I am loading a page, and then would like to perform some functions. I tried to use solutions like window.onload, but that is after my html (blank page with just the JS) loads, I need the function to perform after the page I am reffering to is loaded.
I am using this code:
this.document.location.href = myurl;
And after this loads, I would like to call some function. Is there a way to do so?
Thanks
EDIT:
I can not edit the target page source code.
When you change the value of document.location.href, you are essentially doing a redirect.
You can either just do whatever you want to do within the loaded page itself or if you don't have cross domain issues, do xhr of the page you're wanting to load dynamically, query the body, replace content of your current body and also replace head contents i.e. style, title and scripts etc. You could then execute any script you want.
Extra note: This is quite a tricky thing to do, I've done this a few times before - and its proven quite problematic due to the fact that you don't actually get a fully parsed document object that you can just query so simply, you only receive a huge string. One hack that I've thought of using is actually just loading everything within an iframe allowing easy querying which is actually documented - extra reading here
window.load takes forever to fire because it waits for all images and assets to load on the page.
It sounds like the best solution for you would be to poll for the document to be finished loading. Here's a simple example:
(function poll(){
if(document.readyState === "complete"
{
// Your code here
}
else
setTimeout(poll,500);
})();
Place the 'window.onload = myFunction(){...}' inside the page, which will be loaded.
this.document.location.href
will open the page like you typed it into the browser address bar and your onload-script in the old page will not be executed in the new one.
By the way, you can shortcut it to document.location = myUrl
See the Document-API at Mozilla
First question:
About Dynamic Script Elements
var script = document.createElement ("script");
script.type = "text/javascript";
script.src = "script.js"; document.getElementsByTagName_r("head")[0].appendChild(script);
The important thing about this technique is that the file is downloaded and executed without blocking other page processes, regardless of where the download is initiated. You can even place this code in the <head> of a document without affecting the rest of the page.
I want to know what is difference between Dynamic Script Elements and this codes
<script type="text/javascript" src="script.js"></script>
Why does Dynamic Script Elements download and execute file without blocking other page processes and the other will?
Second question:
I know that the page download and rendering must stop and wait for the script to complete before proceeding, so I put scripts at the bottom before </body>
Is it necessary to use XMLHttpRequest Script Injection or other libraries like lazyload when I put scripts at the bottom, and why?
Anybody know this? Thanks
I want to know what is difference between Dynamic Script Elements and
this codes
Your code snippet is a dynamic script element. It is added dynamically to the page and is not natively present in the HTML of the page.
Script tags present in the HTML of the page are executed sequentially as the browser encounters them during the parsing of the page. The first script element is executed before any others, then the second and so on. Because there can be script elements embedded anywhere in the HTML of the page and they must execute in sequential order, a script element in the page must load and be executed before the rest of the HTML after it can be parsed and added to the page.
Why does Dynamic Script Elements download and execute file without
blocking other page processes and the other will?
I'm not sure what kind of answer you're looking for here. It works this way because this is how the designers of the browser/HTML specs decided it would work. A dynamically added script executes asynchronously, independent of the loading of the page. A script element present in the HTML of the page executes in a predictable order with respect to both other scripts and with respect to the loading of the page elements. This can be very important for some types of scripts (such as document.write() and thus the designers of these specs allow you to have either predictable, sequential order (which by its very nature must block until complete) or asynchronous loading. The defer and async attributes also allow you to change the behavior of even script tags that are present in the HTML of the page. So, this way you can have whichever behavior is most advantageous.
Is it necessary to use XMLHttpRequest Script Injection or other
libraries like lazyload when I put scripts at the bottom, and why?
No, it is not necessary to use script injection. Putting a script at the bottom of the page will allow the page elements above it to show to the user without waiting for the script to execute (if that is your goal). There are many other reasons for dynamically loading scripts besides just page load performance. For example, some scripts are loaded only when needed based on what action the page is going to execute.
For a lot more info about the execution order of scripts including the effect of the defer and async attributes in script tags, see this detailed post: load and execute order of scripts
The position of the script tags has something historical. In the early easy was often document.write() used to the Dom could change that is why a script block can block the rendering. However there is a attribute which says I don't change the Dom go on.
Script tags at the end of the page are related to the time when the download process is triggered so this can optimize the load process.
That lazyload libs are helpful of you need some other frameworks/libs only under some runtime conditions. It's all about page load times and how fast the page react on user interactions.
What are the differences between the two solutions below ?
In particular, is there a good reason to favour 2 over 1. (note: Please assume the name of the script to load is known. The question is just about if there is value in creating a minimal script to load a script in the given situation )
1 - Script At The Bottom
<html>
<body>
...
...
<script src='myScript.js'></script>
</body>
</html>
2 - Script at the bottom loads external script
<html>
<body>
...
...
<script>
// minimal script to load another script
var script = document.createElement('script');
script.src = 'myScript.js'
document.body.appendChild(script);
</script>
</body>
</html>
One important feature of the second one is that it allows the browser to finish parsing the page immediately, without waiting for the script to load. That's because the first example allows the script to use document.write to change the parsing state around the <script> tag, while the second one doesn't.
Now, we know that it's at the bottom of the page so that there isn't any important content left to parse, but this is still an important difference. It's not until parsing is done that the browser fires the popular DOMContentLoaded event. In method 1, the event fires after the script loads and executes. In method 2, the event fires before the script starts loading.
Here are some examples. In these demos, a DOMContentLoaded listener changes the background color to yellow. We try to load a script that takes 3 seconds to load.
http://jsfiddle.net/35ccs/
http://jsfiddle.net/VtwUV/
(edit: Maybe jsfiddle wasn't the best place to host these demos. It doesn't show the result until the slow-loading script loads. Be sure to click Run again once it loads, to see what happens.)
Pick the approach that's best for your application. If you know you need the script to run before DOMContentLoaded, go with method 1. Otherwise, method 2 is pretty good in most cases.
1. Script at the bottom
When you use a "synchronous" script tag, it will block the browser from rendering the page until the script is loaded and executed. This method has the following effects:
Regardless of where you put the script tag, the browser cannot fire DOMContentLoaded until the script is downloaded and executed.
Placing such a script tag at the bottom only ensures that the browsers has rendered all content before getting blocked by the script.
2. Script at the bottom loads external script
When you inject a script tag using JavaScript, it will create an "asynchronous" script tag that does not block the browser. This method has the following effects:
Regardless of where you put the JavaScript code that generates the script tag, the browser executes it as soon as it is available without blocking the page. The DOMContentLoaded fires when it should; irrespective of whether the script has downloaded/executed.
The second approach has the following advantages:
The script that injects a script tag can be placed anywhere including document head.
The script will not block the rendering.
DOMContentLoaded event does not wait for the script.
The second approach has the following disadvantages:
You cannot use document.write in such scripts. If you do, such statements might wipe the document clean.
Asynchronous execution does not mean that browser has finished parsing the page. Keep the script executes as soon as it is available clause in mind.
Execution order is not guaranteed. Example: If you load "library.js" and "use-library.js" using injected script tags, it is possible for "use-library.js" to load and execute before "library.js".
Having said all that, there is another method for loading scripts, with three variations:
<script src="myScript.js" async></script>
<script src="myScript.js" defer></script>
<script src="myScript.js" async defer></script>
Regarding Steve Souders's work: he proposed 6 techniques for loading scripts without blocking. The async and defer attributes introduced in HTML5 cover the Script DOM Element and Script Defer techniques and their browser support is more than enough for you to worry about the other techniques.
These two ways of initializing a script are basically the same, although theres no reason to use the second way if you can directly put in the result. However you can wrap the second example in a $(document).ready() method for example which would lead to sort of a lazy loading effect. This basically means that the page would load first and after the loading of the page is finished it would load the script. Or of course you can create a method which initializes a certain script this way. It's useful when you have a large script which is used only in some situations. This would prevent loading it unless you need it, thus decreasing the overall loading time.
This isn't a direct answer to your question, but it's good to know regardless.
The 2nd approach is sometimes used as a library fallback.
For example, you load jQuery from the Google CDN. But, if it were to fail for any reason, load jQuery from your own local copy.
Here's how the popular HTML5 Boilerplate recommends doing this:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.0.min.js"><\/script>')</script>
The first method means that the script tag is hardcoded in. The second method dynamically adds a script tag to the bottom of the page using JavaScript. The benefit of the second method is that you can add additional logic if needed to modify the script tag. Perhaps you might want to load a different script file based on culture, browser or some other factor you can determine in JavaScript. The second method also causes the JavaScript file to be loaded without blocking the loading of the rest of the web page. In method one the page will stop loading when it gets to the script tag, load the JavaScript file, then finish loading the rest of the page. Since this tag is at the bottom of your page it doesn't make too much of a difference.
If you are creating a Windows Store app using JavaScript then the first method is recommended as this will allow the app to bytecode cache the JavaScript file which will make it load up faster.
basically i have a blank html page that includes a javascript file, and in the javascript file i have this:
function doIt() {
document.writeln("asdf");
}
// could also be setTimeout
setInterval("doIt()", 5000);
When the html page loads, it waits 5 seconds and then will output "asdf" every 5 seconds to the screen. If i hit refresh or f5, nothing happens. When i view the source, the page is blank. Is there any reason why when i view source i dont even see the:
<script type="text/javascript" src="test.js"></script>
on the html page? Im assuming i cant refresh the page because of the blank source. Any ways to resolve this?
Thanks!
You cannot use document.write like this after the page finishes loading.
Instead, you should append to the text of a DOM element.
When the html page loads, it waits 5 seconds and then will output "asdf" every 5 seconds to the screen.
When the page has finished loading, the document is closed and can't be written to. So if you call document.write() after this point, it assumes you mean to call document.open() and completely replace the page. The old document is unloaded to be replaced by the new one you're about to write, which is why you can't view the source of the old page any more.
And because you don't call document.close(), the throbber will keep spinning, waiting for the new document to be completed (which will never happen).
As SLaks said, you should interact with the DOM instead of using document.write() which is generally best avoided (except in a few specific cases to do with writing initial documents to popups or iframes).
thanks guys. i was able to see what you guys meant by having to modify the DOM to add in javascript after the page has loaded. I was able to do that but ran into the same issue:
basically i needed to use setInterval to do some polling to wait for data to be sent to this iframe from the parent, once it received the data, then it would output some javascript (which i created a new script element in the DOM for). but the problem is that the src of that element is pointing to an external url from which im getting some data from, and the way that external source returns the data is by using document.write - which i have no control over.
is there any other option for doing the polling besides using setInterval? i'd like to continue polling until a max timeout, and then if the max timeout is reached, then execute the rest of the page, then i wont have to worry about the document.write issue from the external source.
is another option to make that call to the external source and parse the response and create the dom elements with my javascript?
Just an idea, didn't have chance to test it.
Have your script create blank window and inject script into there to call the external script:
var oWindow = window.open("about:blank", "dummy", "width=0,height=0");
oWindow.document.write("<html>");
oWindow.document.write("<body>");
oWindow.document.write("<" + "script" + " type=\"text/javascript\" src=\"external.js\"></" + "script>");
oWindow.document.write("</body>");
oWindow.document.write("</html>");
oWindow.document.close();
and then read the oWindow.document.body.innerHTML to see the "output" of the external script.