Running external JS function with document.write asyncronously - javascript

We have a website that is supposed to be loading a logo provided by a 3rd party (the logo is a link that allows users to see that our site has been verified by that 3rd party.)
To get this to work, we're told to include a short script in the head
<script type="text/javascript">
//<![CDATA[
var tlJsHost = ((window.location.protocol == "https:") ?
"https://secure.comodo.com/" : "http://www.trustlogo.com/");
document.write(unescape("%3Cscript src='" + tlJsHost +
"trustlogo/javascript/trustlogo.js'
type='text/javascript'%3E%3C/script%3E"));
//]]>
</script>
And another script in the body:
<script language="JavaScript" type="text/javascript">
TrustLogo("https://ourfakesite.com/logo.png", "CL1", "none");
</script>
This all worked fine, initially: the external script is loaded, the function is run, the logo shows up. Perfect.
The problem occurred when the remote site got really slow...all of our pages that load this logo suddenly became very slow as well, since the script is running synchronously.
Ideally, I'd like this to work as if it were designed as an ajax type call...load the page, and after the page is loaded, attempt to load the extra content.
I've tried some combinations of async/defer and using things like ajax, but it seems that because the JS is using a document.write, if the page is fully loaded, the document.write blows away the existing document before writing the new data; the page loads...and then disappears and the logo appears. (I've seen some commentary explaining that this is expected behavior when document.write is used after the page is loaded.)
Is there a way to do this? Is there an alternate path I'm not considering?

Looking at https://secure.comodo.com/trustlogo/javascript/trustlogo.js, the TrustLogo function itself uses document.write (indirectly, the code is minified, but eventually it does), which means you can't use those scripts asynchronously. If you make the first script asynchronous and append that JavaScript file another way, then you have to make the second script asynchronous, and that would mean document.write (within the TrustLogo function) would be called after the main HTML parsing is complete, which in turn means that there'd be an implicit document.open, which would erase your page. :-(
Of course...you could put all of that in an iframe on your main page, so that only the iframe, not your whole page, is impacted. Provided that's not a violation of the terms of use of the logo (obviously, you'd use a relative path for the iframe so their code sees the right domain and such).

Related

Add script to script that contains document.write won't execute

We're using a webprogram that uses ajax and jquery and the like (Netsuite). I want to change something on a page and have tried to use document.ready and window.load to get an external script loaded on the page. I've tried to load the external script in the head and body.. but the contents aren't written. The external file looks for a specific div id and then prepends some code to that. It never works, because the page itself loads dynamically and the div I'm looking for loads when the rest of the page is done. So window.load, etc. never work...
At last I'm in the program itself that loads parts and pieces and am trying to simply write the external script file in there. Now this time the external file has a simple document.write in it, so it's straightforward. In other words, the script is in the middle of html code in the body of the page. (I know this is a terrible way of doing it, but I've got to try something to get this to work....)
According to firebug, it writes the external file where it should be (check!) and firebug shows me the contents of that file (check!), but ... it never 'writes' it onto the page...
The file just contains this:
document.write('<div id="shpblk" style="border:2px solid #ffa500;border-radius:7px;color:#000066;margin:5px;padding:5px;text-align:left;"><img border="0" width="12" height="12" src="/images/icons/store/icon_exclamation2c.gif">Hazardous conditions blahblah... Potential delays and disruptions can be anticipated.</div>');
What am I missing?
Edit: some more clarification is necessary...:
Situation: I have to be able to put a piece of html on the page every now and then that creates a message.
Environment: What I have is a page that loads a header and footer first (which are set up in separate files) and then it takes a second or so to load the rest of the page. From what I understand, this "rest of the page" is written in a certain code, similar to javascript/jquery.
What I CAN do is: edit the files for the header and footer and put javascript in there to make modifications to the rest of the page. I can access some of the files that contain parts and pieces of the "rest of the page", but this is a huge pile of spaghetti.
What I've tried:
Since I want to be flexible with the html that I need to put into the page, I preferably would like to create a piece of javascript or html or whatever on another site and have the "environment" pick up that code. I can do this with javascript or iframe. But since it's a secure area (https), I thought it would be best to use a javascript file instead of an iframe. So....
I created the javascript file and tried it out in a normal environment where I knew for sure it would work.. and it works like a charm. But when I tried this in the before mentioned "environment", I am running against a wall...
The javascript file has document.ready jquery statement in it and it would prepend the html div to an existing div on the page.
This way it would load the page and write the page.. easy as pie.
However.. since the header and footer load first (which includes the external script file), and then the rest of the page, SOMEHOW the div where the script checks for DOES NOT EXIST YET. So I tried window.load instead of document.ready. Same result.
Now, it WOULD appear ONLY when I refresh the page. So there may be a way to have it refresh the page, but I only want this as the absolute last attempt.
So then I tried to see if I could go around this by changing the script so that, instead of using a document.ready it would just do a simple javascript document.write statement.
Then I call the script in the middle of the body of the page (I put it in one of the files that load in the middle of the page). I know this is not something I would do normally, but wanted to try it out anyway. So.... I would have something like this:
<div id="block1">
<div id="block2">stuff here<div>
<script type="text/javascript" src="https://someotherdomain.com/include.js" ></script>
<div id="block3">stuff here<div>
<div id="block4">stuff here<div>
</div>
Now when I run this, I do not get any errors, but nothing is being done with the contents of that js file. In firebug it shows me the contents of that file though.. so I assume it's being read.
But I have no idea why it doesn't run.
Again.. back to 'normal' practices: I've tried window.load, because this would run the statement after the page loads, HOWEVER.. like I said before, I have the feeling it builds the contents of the (middle of the) page through this somehow and my script runs before this; it cannot find the div (block3) where it would prepend to. Whenever I stop running the page at my script, the div it's depending on doesn't exist yet...
I hope this made sense...
Solution
For the external script file to work as expected, OP will need to load it using an asynchronous script tag like this:
<script type="text/javascript" src="include.js" ></script>
Yet, the file contains a document.write() statement, which is generally something to avoid. A better alternative would be remove document.write() from the file and save it as a plain HTML file. This could then be safely loaded using using jQuery:
$("#include1").load("include.html");
( Requires adding a target DIV to the page where the content should load. )
DETAILS
The question doesn't tell us how the external file is included on the page. And without that information it's difficult to understand the problem or provide a solution ... which is probably why this question has gone unanswered.
Yet, let's assume the the script is being injected into the page on the client side using JavaScript or jQuery. And if that's true then it will fail if not done the correct way.
Let's look at some ways we might add the script to the page:
These script tags will all fail because the file contains a document.write statement and the script is loaded asynchronously.
<script type="text/javascript" src="include.js" async ></script>
<script type="text/javascript" src="include.js" defer ></script>
<script type="text/javascript" src="include.js" async defer ></script>
The browser does load the file, but reports:
Failed to execute 'write' on 'Document': It isn't possible to write
into a document from an asynchronously-loaded external script unless
it is explicitly opened.
This jQuery sort of works. It loads the script, but the document.write implicitly calls document.open, which erases the original content of the page. That's probably not what OP wants.
$.getScript('include.js');
This synchronous method works so long as the document.write is executed on load, i.e., is not inside function called later. So this is a possible solution for OP.
<script type="text/javascript" src="include.js" ></script>

Can dynamically loaded functions finish writing the page that dynamically loaded them

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.

Two different ways of putting the script at the bottom - what are the differences?

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.

document.write is behaving weirdly in Youtube videobar's javascript

Youtube's Videobar is an outdated widget. Google is still serving the js but the documentation and links have been taken off from their site. You can see a running example of this over at: sicmaui.com (right side, youtube tab)
Its currently being loaded using a script tag on html
<script src="http://www.google.com/uds/api?file=uds.js&v=1.0&source=uds-vbw" type="text/javascript"></script>
GSearch.setOnLoadCallback(somefunction); //works
But it doesn't work when I try to load this using the following code
var $script = $('<script></script>').attr('src', src).bind('load', function(){
GSearch.setOnLoadCallback(somefunction); //GSearch is undefined
});
$('head')[0].appendChild($script[0]);
Now the js is being loaded perfectly fine. But the variable is undefined.
I digged into the google's js and found that later on its loading another js file using this code:
google.loader.writeLoadTag("script", google.loader.ServiceBase + "/api/search/1.0/8c68537a8c14de310f268bd7f81c9c67/default+en.I.js", false);
which makes a call (where 'n' equals document)
n.write('<script src="' + b + '" type="text/javascript"><\/script>')
Now ideally this js should overwrite the entire page contents with this script. But for some reason it isn't doing so and this is driving me nuts!
Either way, my primary goal is to load this file asynchronously.
You should try using jQuery's getScript; it handles all the mess you don't want to be involved in: adding the async attribute, defining both readystatechange and load event handlers, avoiding memory leaks, …
Edit:
As for your root problem: I don't think that you can make this script work if you load it asynchronously. document.write is synchronous by nature. See this related question: Warning: A call to document.write() from an asynchronously-loaded external script was ignored. How is this fixed?

Why are external js scripts often loaded with document.write() at the bottom of an HTML page?

An example of this is Google analytics:
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
Would it be just as good just to replace the document.write() with the literal value:
<script type="text/javascript" src="http://www.google-analytics.com/ga.js">
? I'm guessing that the tag is output with document.write() only because the value of gaJsHost ('http://www.') isn't known ahead of time. But if it was known, would there be any reason to output the script tag with document.write() instead of including it literally?
Scripts by default, when encountered on a html page, block the rest of the page from loading. Only when they've finished downloading and executing does the rest of the page continue to get loaded. From High Performance Javascript by Nicholas C. Zakas:
This is a necessary part of the page’s life cycle because the script
may cause changes to the page while executing. The typical example is
using document.write() in the middle of a page (as often used by
advertisements).
By inserting the script dynamically, as is being done above, you can overcome that behaviour - no page blocking - the loads happen asynchronously.
By putting the thing at the bottom of the page, you ensure the html and css are loaded before the javascript. This way, while the javascript is loading, the user can already see the page.
It's all about performance.
to ensure that the browser loads them after the page is rendered.
It is a performance thing.
There are a couple of likely reasons:
1. To ensure that some part of the DOM already exists on the page before the javaScript file is loaded. This prevents you from trying to manipulate uncreated DOM elements.
2. To speed up stuff; browsers typically go into single-threaded mode when loading javaScript so it is best to delay it if you don't really need it at the onset.
I would refer to a great resource about that first:
http://webreflection.blogspot.com/2009/12/documentwriteshenanigans.html
So after reading this, I can see the advantage is script is loaded after the page has been rendered.
It is the fastest way to add a script-generated text into the page[the browser doesnot have to modify the DOM structure].So used for inserting advertising scripts [downfall if ad server is slow].Adding user generated data to the url.Prevents caching by adding random values.
basically used for its speed.

Categories

Resources