I have an iframe that has a onload event. This event called a function (iframe_load) that I placed into a server side script. It appears that when my screen is launched, the onload event is triggered before the server side script has loaded and I get an error as the function is not found.
I have got around this by changing the onload event to call a checking function (iframe_check_load) in the client side script. This checks for the existence of parameter in the server side script, where if found it will then call the original function (iframe_load).
However ideally I would prefer not to have this checking function and to keep the client side code to a minimum. Is there a way I can add some code to the onload event to do this check, without having to use the checking function?
My current code:
function iframe_check_load(ctrl) {
if(typeof iframe_flag != "undefined"){
iframe_load();
}
}
<IFRAME id=iFrame2 onload=iframe_check_load() ></IFRAME>
I am sure there must be better ways to do all of this, please go easy as I'm still learning JS!
Since that there's no guarantee that the script is loaded before the frame, or vice versa, at least one checking must be performed in order to know if the external script is already available when the frame is loaded.
If the frame is loaded before the external script is available, you can use ONLOAD attribute on the element that load the external script to notify that it's already loaded. This will ensure that the iframe_load is always called. Assuming that there's no network error.
<SCRIPT>
//the saved "ctrl" parameter for iframe_load if
//the frame is loaded before custom_scripts.js.
var ctrlParam; //undefined as default
//script loaded handler for custom_scripts.js
function customScriptLoaded() {
//call iframe_load only if ctrlParam is not undefined.
//i.e.: frame is already loaded.
//will do nothing otherwise. leave it to iframe_check_load.
if (typeof ctrlParam != "undefined") {
iframe_load(ctrlParam);
}
}
//check whether it's safe to call iframe_load.
//assuming that "iframe_flag" is defined by custom_scripts.js.
function iframe_check_load(ctrl) {
if (typeof iframe_flag != "undefined") {
//custom_scripts.js already loaded.
//call iframe_load now.
iframe_load(ctrl);
} else {
//custom_scripts.js not yet loaded.
//save parameter and defer call to iframe_load.
//iframe_load will be called by customScriptLoaded.
//ctrl parameter must not be undefined in order to work.
console.log('Error: ctrl parameter of iframe_check_load is undefined. iframe_load will never be called.');
ctrlParam = ctrl;
}
}
</SCRIPT>
<!--Note: Don't forget to duble-quotes attribute values-->
<SCRIPT id="custom_scripts" type="text/javascript" src="htmlpathsub/custom/custom_scripts.js" UserSuppliedFullPath="1" onload="customScriptLoaded()"></SCRIPT>
<!--Using "this" (the IFRAME element) as the "ctrl" parameter-->
<IFRAME id="iFrame2" onload="iframe_check_load(this)"></IFRAME>
Related
Can somebody explain here, why I get the alert before the redirect?
and is there a way to switch them?
function test() {
window.location.href="https://www.google.com";
window.onload = alert("It's loaded!")
}
here is an example:
jsbin: https://jsbin.com/zenidafihu/3
There are three different issues here:
Loading a new location is async
Assigning a new value to location won't stop everything until the new page has loaded. It will assign the value and then, at some point in the future, the browser will load the new page. In the meantime, everything will keep going as normal.
onload expects to be passed a function
alert("It's loaded!") calls the alert function (immediately) and is evaluated as the return value of that call (which is not a function). That return value is then assigned to onload.
To assign a function, you need to have an actual function, such as:
onload = alert.bind(window, "It's loaded!");
or
onload = function () { alert("It's loaded!"); };
Each page is a separate JS environment
When you leave the page, you create a new execution environment. All variables and data is lost. (Although you can store stuff via localstorage and cookies, and pass stuff to other origins through URLs).
It isn't possible for a page you are leaving to do anything to the page you are going to. You can't set an onload handler for the next page.
The redirection won't start until your current Javascript thread has finished executing. So nothing will happen re the location until the function ends i.e. until the Alert has been dismissed.
JavaScript is asynchronous language. So code for your alert will not wait for complete execution of your first statement i.e. redirection.
The code snippet below is from the book JavaScript: The Definite Guide.
I have some questions about it. From my point of view, I don't anticipate any scenario where there is a must to use the onLoad function.
I think that this chunk of code has to be used as global javascript instead of as part of an event handler. If it is invoked in an event handler of a button, the load event on window must have already been triggered. As a result, the registered function will never be invoked.
However, if it is used as the global javascript, onLoad.loaded is always false when the onLoad function is invoked.
Why not just register the load event on window, instead of checking whether onLoad.loaded is true or false?
// Register the function f to run when the document finishes loading.
// If the document has already loaded, run it asynchronously ASAP.
function onLoad(f) {
if (onLoad.loaded) // If document is already loaded
window.setTimeout(f, 0); // Queue f to be run as soon as possible
else if (window.addEventListener) // Standard event registration method
window.addEventListener("load", f, false);
else if (window.attachEvent) // IE8 and earlier use this instead
window.attachEvent("onload", f);
}
// Start by setting a flag that indicates that the document is not loaded yet.
onLoad.loaded = false;
// And register a function to set the flag when the document does load.
onLoad(function() {
onLoad.loaded = true;
});
I think you misunderstand the usage scenario.
You are right, the above snippet should be executed on startup, before the webpage completes loading, so that onLoad.loaded is accurately assigned.
However, the onLoad function that is defined by the script can be invoked from anywhere, later, even from button event handlers etc.
I'm currently working on a script to be placed on a 3rd-party site...in order to test it I'm opening the 3rd party's site and running the script in the browser's console (Chrome). Some code I need to executed on window.load(), but that code isn't being executed with this method of testing. I'm assuming it's because the code bound by load to the window is being bound after the load event has taken place, thus never being triggered. My question has two parts:
Is the reason that window.load is not being triggered in fact because it's being added after the load event has been triggered? Or is this wrong and there is likely a problem elsewhere?
How best can one simulate events triggered on load when appending javascript through the console like this?
if(document.readyState === "complete"){ will detect if the load is already complete.
You could easily use an else and then put in the load event handler if it hasn't finished loading yet. Something along the lines of:
if(document.readyState === "complete"){
// do stuff
}else{
// attach load handler
}
What I like to do is define a pageLoaded type function that I can run at a later point with my code, that way I can call it immediately if the page is already loaded, or let the load handler call it when the page load does fire. Something like:
var pageLoaded = function(){alert("Page is ready!");}
if(document.readyState === "complete"){
pageLoaded()
}else{
// attach load handler, calls pageLoaded()
}
Of course, since you tagged your question as jQuery you could always just wrap all your code in jQuery's handy dandy ready function shorthand:
$(function(){
// do stuff
});
This passes your anonymous function to jQuery where it will do something very similar if not identical to the above vanilla javascript.
Define your event in a function and then call that function from the console.
function do_this_on_load() { alert("Loaded!") }
$(window).load(do_this_on_load);
Then you can from the console run:
do_this_on_load();
to see what it does on the page.
I understand that JS is single threaded and synchronously executed. Therefore when i add a file to my browser head tag that file is executed as soon as its encountered. Then it goes to the next script tag & executes that file. My question is when I add a js file dynamically to an HTML head tag. How does the browser executes that file?
Is it like that the file is executed as soon as the file is loaded wherever the current execution is. Or is it that we can control how that file is executed?
When the script is loaded, it will be executed as soon as possible. That is, if some other javascript function is executing, like a clickhandler or whatever, that will be allowed to finish first - but this is a given because, as you say, in browsers JavaScript normally execute in a single thread.
You can't control that part of the script loading, but you could use this pattern - heavily inspired by JSONP:
inserted script:
(function () {
var module = {
init: function () {
/* ... */
}
}
ready(module); // hook into "parent script"
}());
script on main page:
function ready(o) {
// call init in loaded whenever you are ready for it...
setTimeout(function () { o.init(); }, 1000);
}
The key here is the ready function that is defined on your page, and called from the script you insert dynmaically. Instead of immediately starting to act, the script will only tell the parent page that it is loaded, and the parent page can then call back to the inserted scripts init function whenever it wants execution to start.
What happens when a JavaScript file is dynamically loaded ( very simplified, no checks ):
the file is loaded;
if there is function call e.g. doSomething() or (function(){...})(), the code is executed(of course you must have the definitions);
if there are only function definitions, nothing is happening until the function call.
See this example: 3 files are loaded, 2 are executed immediately, 1 is waiting the timeout.
Edit:
The script tag can be placed anywhere in the page. Actually it is better to be placed at the end of the page if the onload event is not used (yahoo speed tips).
With HTML5 JavaScript has web workers MDN MSDN wikipedia.
Considering a way to do this is
var js=document.createElement('script')
js.setAttribute("type","text/javascript")
js.setAttribute("src", filename)
document.getElementsByTagName("head")[0].appendChild(js);
// ^ However this technique has been pointed to be not so trusworthy (Read the link in the comment by Pomeh)
But answering your question
How does the browser executes that file?
As soon as the script is added to the DOM
Is it like that the file is executed as soon as the file is loaded wherever the current execution is?
Yes
Or is it that we can control how that file is executed?
Its better if you attach an onload event handler, rather than a nasty tricks.
Here is some code you can try to get an answer to your question.
<script>
var s = document.createElement('script'), f = 1;
s.src="http://code.jquery.com/jquery-1.7.2.js";
document.head.appendChild(s)
s.onload = function(){
console.log(2);
f = 0
}
while(f){
console.log(1);
}
</script>
This code should ideally print a 2 when the script loads, but if you notice, that never happens
Note: This WILL kill you browser!
This code is just stuck in the Body it does exactly what I expect but I don't understand WHY.
Particularly I dont see how the webservice gets called, it looks like the script adds the call to the Head section and maybe reloads the page but I'm not sure and don't like not knowing or what this line means - script.onload = script.onreadystatechange = function ()
Can anyone explain please?
var script = document.createElement("script"),
head = document.getElementsByTagName("head")[0],
url = "https://services.postcodeanywhere.co.uk/PostcodeAnywhere/Interactive/FindByPostcode/v1.00/json.ws?";
// Build the query string
url += "&Key=" + encodeURI(pca_Key);
url += "&Postcode=" + encodeURI(postcode);
url += "&CallbackFunction=PostcodeAnywhere_FindByPostcode_End";
script.src = url;
// Make the request
script.onload = script.onreadystatechange = function () {
if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") {
script.onload = script.onreadystatechange = null;
if (head && script.parentNode)
head.removeChild(script);
}
}
head.insertBefore(script, head.firstChild);
Stu
Basically, it's making a JSONP call to get some data from postcodeanywhere.co.uk. JSONP uses script elements. The script from postcodeanywhere.co.uk will call the function identified by the CallbackFunction argument on the script URL, passing it a JavaScript object literal, something like this:
PostcodeAnywhere_FindByPostcode_End({
name: value
})
You haven't shown it, but presumably there's a function with that name defined at global scope in the script making the call.
This is to work around the SOP, which doesn't allow ajax calls cross-origin.
How it does it is by creating a script element, assigning it the src URL, appending it to the page, and then hooking the readystate event so it can clean up after itself by removing the element again. (That last bit isn't quite what it could be, not all browsers fire the readystate event on script elements, to do this thoroughly you have to hook both readystate and load. Or do the cleanup in the callback. But having the script element lying around is harmless.) It should also be using encodeURIComponent, not encodeURI. And there's no need for the stuff with the head element, you can just append the script directly to document.documentElement.
This script grammatically creates <script/> HTML tag with given src URL and appends it to the beginning of the <head> in the page DOM:
<head>
<script src="https://services.postcodeanywhere.co.uk/PostcodeAnywhere/Interactive/FindByPostcode/v1.00/json.ws?&Key=...&Postcode=...&Postcode="></script>
<!-- the rest of the HEAD -->
</head>
It also attaches event handler to both onload and onreadystatechange. This event is triggered when the script is loaded. Interestingly, it removes the event handler and the <script/> tag once it is loaded, cleaning up after itself.
Probably the script runs some code immediately after being downloaded for its side-effects. E.g. it creates a global object or modifies the DOM. Once the script is done, it is removed for some reason.
1) It creates a DOM element,
2) puts it in the head element, thus downloads it.
3) Executes it
4) Removes the DOM element.
Note that any global functions and variables will be available later, so code from it could be executed, and variables accessed after it is removed.