I have intergrated a third party code into my website, and suddenly the setTimeout and setInterval stopped working: Before the third party is loaded, everything works fine. setTimeout and setInterval that were scheduled to run after the third party is loaded, do not dun at all.
After removing the 3rd party code snippet they supplied, everything work.
My question is - how can it be? what can the third pary do that can stop my schedules?
I renamed any pointers to the returned value of the setTimeout function; I tried to play with the place where I put the snippet and / or the setTimeout code.
Nothing work.
It doesn't make any sense. and I don't know how to start debugging it.
Here is a simplified html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My Demo</title>
<link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico"/>
<!--<link href="css/style.css" rel="stylesheet" type="text/css">-->
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
</head>
<body>
<script>
<!-- the alert pops up only when I remove the 3rd party snippet -->
setTimeout(function(){
alert("done");
}, 5000);
</script>
<!-- This is the 3rd party code -->
<script type="text/javascript">
var $P; var prefix = ('https:' == document.location.protocol ? 'https://' : 'http://'); var _P = _P || [];
_P.push(['setId', '123']);
var PPP = document.createElement('script');
PPP.type = 'text/javascript'; PPP.src = prefix + 'thethirdpartyIuse.com/functions.js';
var s = document.getElementsByTagName('script');
var lastScriptTag = s[s.length - 1];
lastScriptTag.parentNode.insertBefore(PPP, lastScriptTag);
</script>
</body>
</html>
Any help & guideness is appriciated!
Are you sure? It works fine in liveweave: http://liveweave.com/OKMyjs
And indeed you should wrap your code in:
window.onload = function() {
//your stuff
}
May be the external code redefines alert as something else. To see if this is the issue try changing your code to:
(function(myalert){
setTimeout(function(){
myalert("done");
}, 5000);
})(alert);
If this doesn't work the only reason I can think to is that the external script goes into an infinite loop. Functions registered with setTimeout will be executed once the Javascript event loop starts after the synchronous execution of script tags in the page and this may never happen if any toplevel stript hangs.
You should however see in this case the loading is taking forever (loading animation in the browser) and after long enough the browser should signal that there is a problem loading the page.
Something redefines your alert function.
Possible solutions:
wrap your code in (function(alert) { /* your code */ }(alert))
Object.defineProperty(window, 'alert', { configurable: false, enumerable: true, value: alert, writable: false }); to protect your alert from redefining.
do not rely on alert (in 99% of cases modal or console.log are superior solutions - alert, prompt and confirm are three functions blocking code execution in JavaScript).
After a lot of debugging, I found the probelm:
The 3rd party did setTimeout(true)for some reason (I assume by mistake).
In chrome, it cancel all schedules (setTimeout & setInterva).
I report the problem.
Related
When I run my code in console it works fine, but when I load the page it gives me an error - TypeError: undefined is not an object (evaluating 'rowInfo.textContent')
I have two webpages one that is the parent and the other that is the child. They are both on the same local server using the same protocol and port. I have a third file that holds the javascript. Here is the relevant code:
Parent Page
<html>
<head>
<title>Broker's Lead List</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://c1eru548.caspio.com/scripts/embed.js"></script>
</head>
<body>
<div id="callback"></div>
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript">
autoRefresh_div();
window.frames['DueDateCounter'].addEventListener("load", alert("loaded"));
popUpWindow();
</body>
</html>
Javascript code
function autoRefresh_div() {
$("#callback").empty()
.html('<iframe name="DueDateCounter" title="DueDateCounter" ' +
'style="width: 1px; height: 1px" ' +
'src="https://192.168.0.50/CRM/CalanderCountDown.html">Sorry, but// your browser does not support frames.//</iframe>');
}
var f, doc, rowInfo, minutesUntilCallBack, calenderItem, calenderItemId;
function popUpWindow() {
f = $('iframe')[0];
doc = f.contentDocument? f.contentDocument: f.contentWindow.document;
rowInfo = doc.getElementsByTagName('td')[0];
minutesUntilCallBack = rowInfo.textContent;
calendarItem = f.contentDocument.getElementsByTagName('td')[1];
calendarItemId = calendarItem.textContent;
alert(minutesUntilCallBack);
alert(calendarItemId);
}
After the page has loaded and I go to the console, I can see that the variable f is defined, but nothing else is defined. Now if I use the console and put the code in everything works fine. The minutesUntilCallBack alerts and so does the correct calendarItemId.
I thought it might have been a problem with the iframe not being loaded properly, so I put a listening event in, that I have to OK before I run the function popUpWindow() that looks into the iframe.
I've read lots of posts about similar issues across many sites, but can't seem to get to the correct answer.
Any help much appreciated.
You need to put the popUpWindow() function inside of the onload event listener for the iframe. It is currently running before the iframe has loaded. addEventListener is asynchronous.
window.frames['DueDateCounter'].addEventListener("load", function() { popUpWindow(); });
We give out a piece of javascript tags such as <script src="http://ours.com/some.js"></script> which site owners put on their site like http://example.com and in this javascript tag we want to dynamically include a third-party js such as which can have document.write in it, but of course if we try to include it by conventional method,
var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
script_tag.src="http://third-party.com/some.js";
document.getElementById('target').appendChild(script_tag);
we get a warning from browser,
Warning: A call to document.write() from an asynchronously-loaded
external script was ignored.
How do we get around this? Keep in mind, we don't really have control over third-party scripts so we can't change the logic in it. We are looking for some solution which can work across all browsers.
The problem with loading a script on a already loaded document (instead of having the browser ignore the document.write()) is that you would delete all existent HTML. See this example so you can understand exactly what's happening, or for more details look at a documentation page for the document.write() method.
While I know this might not be what you're expecting to get as an answer, I believe you are out of luck since rewriting the script is not an option.
This appears to be a similar question with similar replies.
You can support script injection the correct way by intercepting calls to document.write in this way:
document.writeText = document.write;
document.write = function(parameter) {
if (!parameter) return;
var scriptPattern = /<script.*?src=['|"](.*?)['|"]/;
if (scriptPattern.test(parameter)) {
var srcAttribute = scriptPattern.exec(parameter)[1];
var script = document.createElement('script');
script.src = srcAttribute;
document.head.appendChild(script);
}
else {
document.writeText(parameter);
}
};
Obviously this can be condensed down a bit further, but the variable names are included for clarity.
Source
How about instead of loading the script by appending a script element, you load the contents of the script URL with an AJAX call and then use eval() to run it in the global scope? Here's an example and I did test it to verify that it works:
<!DOCTYPE html>
<html>
<head>
<script>
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
window.eval(xmlhttp.responseText); //Indirect call to eval to execute in global scope (http://perfectionkills.com/global-eval-what-are-the-options/)
}
}
xmlhttp.open("GET", "https://third-party.com/test.js", false); //This is synchronous so that any document.write calls don't overwrite the entire page when they get called after the document is finished rendering. For all intents and purposes, this just loads the script like any other script, synchronously.
xmlhttp.send();
</script>
</head>
<body>
<div><h2>Hello World</h2></div>
</body>
</html>
And here are the contents I had in the test.js file:
document.write("This is a test...");
alert("...This is a test alert...");
console.log("...And a console message.");
I made the AJAX request for the script synchronous so that it would be loaded exactly as if it were a regular embedded script tag. If you run it asynchronously, and the script uses document.write after the page has been fully rendered, it clears the DOM and then writes to it... Kind of annoying actually. Lemme know if this works for you. :)
Document.write will not work from async script because document is already loaded when script starts working.
But you can do this:
document.body.innerHTML = document.body.innerHTML + '<h1>Some HTML</h1>';
Another procedure is to change the behavior of document.write() function.
Assume you have the main index.php file:
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
Hello<br>
<div id="target"></div>
<script>
document.write = function(input) {
document.body.innerHTML += input;
}
var doit = function() {
var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
script_tag.src="http://127.0.0.1:8080/testPlace/jsfile.js";
document.getElementById('target').appendChild(script_tag);
}
</script>
</body>
</html>
and the jsfile.js is like this:
document.write("OK MAN!");
now if you type doit() in the js browser console to execute that function (and the script do what you wrote) then the result would be:
Hello
OK MAN!
In which the html is like this:
<html><head>
<meta charset="utf-8">
</head>
<body>
Hello<br>
<div id="target"><script src="http://127.0.0.1:8080/testPlace/jsfile.js" type="text/javascript"></script></div>
<script>
//That Script which here I removed it to take less space in answer
</script>
OK MAN!</body>
</html>
What is the 3rd party javascript file?
If it's Google Maps JavaScript API v3 then make sure you include "&callback=your_init_funct" in the script URL. Then it will call 'your_init_funct' once the maps library is loaded so that you can begin displaying the map.
Another solution would be bezen.domwrite.js which is available here: http://bezen.org/javascript/index.html
Demo: http://bezen.org/javascript/test/test-domwrite.html
Yes, document.write can't be called from an asynchronously loaded script, because it's detached from the document, so it can't write to it.
You can see the approach used here for the google maps api to get around this problem. So, it is possible some of your 3rd party scripts that you haven't named, could have the similar callback pattern implemented.
https://developers.google.com/maps/documentation/javascript/examples/map-simple?hl=EN
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
async defer></script>
</body>
</html>
Can anyone tell me why does this $.ajax() cause the webpage to do a postback twice? Isn't it suppose to fire only once?
This is what I saw when debugging in Visual Studio and it is causing the server-side script to run twice. I'm using JQuery version 2.0.0 .
The ThrobblerAnimationBegin() function is what show the processing icon animation to let the end-user know the webpage is busy executing the script. The #{} bracket is the server-side script, this is how I was able to tell when a postback was made to the server-side backend, by using debugging breakpoint.
Thanks...
#{
string foo = "Me Me Me";
foo += ", fee fee fee";
}<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>BookItOut - A New Dawn In Auto Pricing"</title>
<script type="text/javascript" src="~/Member/Scripts/jquery-v2.0.3/jquery-v2.0.3.min.js"></script>
<script type="text/javascript">
function ThrobblerAnimationBegin() {
return $.ajax();
}
function ThrobblerAnimationEnd() {
}
$(document).ready(function () {
function DrawVehicleCostPerDays() {
var $deferred = $.Deferred(); //$.Deferred.done() --> to allow ayschronous sleep/delay until this current function() is finish before running done() afterward to continue. [[http://stackoverflow.com/questions/12116505/wait-till-a-function-is-finished-until-running-another-function]]...
$deferred.resolve();
return $deferred;
}
//Load the script...
ThrobblerAnimationBegin().done(function () {
//alert("done");
DrawVehicleCostPerDays(
).done(function () { ThrobblerAnimationEnd(); /*alert('success');*/ }
).fail(function () { ThrobblerAnimationEnd(); /*alert('failed');*/ });
});
});
</script>
</head>
<body>
</body>
</html>
EDIT as per request Here's the snapshot from Firefox's Firebug.
Your ajax is not firing twice. Instead, what you are seeing is the initial page load (what you are counting as the first ajax request) and then the ajax request (what you were counting as the second). Since you did not specify a URL in the .ajax() call, it made a request to the same page, which is likely what confused you.
You should probably read the .ajax() documentation for simple examples of how to use it.
I've been sifting around the web trying to find out whats going on here and I have not been able to get a concrete answer.
I have one $(document).ready on my site that seams to run multiple times regardless of the code that is inside it.
I've read up on the bug reports for jQuery about how the .ready event will fire twice if you have an exception that occurs within your statement. However even when I have the following code it still runs twice:
$(document).ready(function() {
try{
console.log('ready');
}
catch(e){
console.log(e);
}
});
In the console all I see is "ready" logged twice. Is it possible that another .ready with an exception in it would cause an issue? My understanding was that all .ready tags were independent of each other, but I cannot seem to find where this is coming into play?
Here is the head block for the site:
<head>
<title>${path.title}</title>
<meta name="Description" content="${path.description}" />
<link href="${cssHost}${path.pathCss}" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="media/js/fancybox/jquery.fancybox.pack.js" type="text/javascript" ><!-- --></script>
<script src="/media/es/jobsite/js/landing.js" type="text/javascript" ><!-- --></script>
<script src="/media/es/jobsite/js/functions.js" type="text/javascript"><!-- --> </script>
<script src="/media/es/jobsite/js/jobParsing.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="/media/es/jobsite/js/queryNormilization.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery/jquery.metadata.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery/jquery.form.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery.i18n.properties-min.js" type="text/javascript" charset="utf-8"><!----></script>
<script type="text/javascript" charset="utf-8">
function updateBannerLink() {
var s4 = location.hash.substring(1);
$("#banner").attr('href','http://INTELATRACKING.ORG/?a=12240&c=29258&s4='+s4+'&s5=^');
}
</script>
</head>
Pay no attention to the JSP variables, but as you can see i'm only calling the functions.js file once (which is where the .ready function exists)
The ready event cannot fire twice. What is more than likely happening is you have code that is moving or manipulating the element that the code is contained within which causes the browser to re-execute the script block.
This can be avoided by including script tags in the <head> or before the closing </body> tag and not using $('body').wrapInner();. using $('body').html($('body').html().replace(...)); has the same effect.
It happened to me also, but I realized that the script had been included twice because of a bad merge.
This happened to me when using KendoUI... invoking a popup window would cause the document.ready event to fire multiple times. The easy solution is to set a global flag so that it only runs once:
var pageInitialized = false;
$(function()
{
if(pageInitialized) return;
pageInitialized = true;
// Put your init logic here.
});
It's sort of hack-ish, but it works.
Make sure you don't include JS file twice. That was my case
You might consider to use
window.onload
instead of
$(document).ready
try putting this in your functions.js to prevent it from being executed twice :
var checkit = window.check_var;
if(checkit === undefined){ //file never entered. the global var was not set.
window.check_var = 1;
}
else {
//your functions.js content
}
however i suggest that you look more into it to see where are you calling the second time.
I had a similar problem when I was trying to refresh a partial. I called a return ActionResult instead of a return PartialViewResult. The ActionResult caused my ready() to run twice.
There is a possibility to encounter this problem when you add same controller twice in the html.
For an instance:
[js]
app.controller('AppCtrl', function ($scope) {
$(document).ready(function () {
alert("Hello");
//this will call twice
});
});
[html]
//controller mentioned for the first time
<md-content ng-controller="AppCtrl">
//some thing
</md-content>
//same controller mentioned again
<md-content ng-controller="AppCtrl">
//some thing
</md-content>
I had a similar issue today. A <button type="submit"> caused the $(document).ready(...) event to fire again in my case. Changing the code to <button type="button"> solved the issue for me.
See document.ready function called again after submit button? here on stackoverflow for more details.
In my case $(document).ready was firing twice because of bad CSS, check if any part of your CSS has background-image: url('');
If the iframe doesnt show anything and is used for other reasons (like uploading a file without reload) you can do something like this :
<iframe id="upload_target" name="upload_target" style="width:0;height:0;border:0px solid #fff;"></iframe>
Notice that src is not included that prevents the second on ready trigger on the document.
I had this problem with window.load function was executed twice:
The reason was because I had reference to the same javascript-file in the main page as well as a .net usercontrol. When I removed the reference in the main page, the load-function was only executed once.
I had this happen to me this morning... and what I discovered after closely examining some html code in a jquery modal form that I had recently manipulated, that I'd accidentally removed a closing table tag. I haven't taken the time yet to fully understand why that caused the document.ready function to be called twice, but it did. Adding the closing table tag fixed this issue.
jQuery JavaScript Library v1.8.3 (yes, it is a legacy app)
My problem was that I had tags referencing my JS file in both my index.cshtml file AND my _Layout.cshtml. This was causing the document.ready function to fire twice, which was causing DataTables to bomb.
THE QUESTION
Interesting one that probably has a simple solution. With the help of #jessegavin I've added a jQuery function to my page that controls the playback of HTML5 audio elements on the page. The code is beautiful and works correctly on a jsFiddle, but not when put into the context of my page.
I've thrown time to the wind and methodically stepped through this to try and isolate my mistake, but with no avail. Really, I went Aristotle on this one and applied the scientific method. Please forgive me for the heft of this question. It's really my last resort.
THE NITTY GRITTY
Here are my findings: All the JavaScript functions for the page work correctly in context of the jsFiddle. After specifically adding the functions one at a time I can say that they each work appropriately, and that all except for the HTML5 audio playback work on both the jsFiddle and the live page. That is to say ONLY the HTML5 audio playback is not working on the live page.
All the HTML is 100% validated, all the CSS is 100% validated. Both groups are code are added into the jsFiddle in their entirety.
The page heading loads (in this order) an external CSS document, jQuery 1.5.1 and jQuery UI 1.8.8 (same on jsFiddle, except for UI, which is 1.8.9) via Google's onload command, an external JavaScript document (where ALL functions for the site reside), and finally a Google Analytics function.
The JavaScript is wrapped in a document ready framework.
My guess is that the discrepancy lies somewhere in the head, but I cant imagine what exactly it is. All the external links work correctly, evidenced by the JavaScript functions working correctly (except for the new audio controller).
THE POST SCRIPT
P.S.- Only works in Chrome and Safari as of yet.. The server I'm hosting the two audio files off of doesn't have the correct ht-access file declaring OGG as a correct MIME type. I'll start a question for that too.
RESOURCES
jsFiddle: http://jsfiddle.net/66FwR/3/
HTML (heading only, body is in jsFiddle)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8>
<meta name="description" content="Fernando Garibay- Producer, Songwriter, Artist, Multi-Instrumentalist, and Programmer" />
<meta name="keywords" content="Fernando Garibay, Music, Producer, Songwriter, Artist, Mutli-Instrumentalist, Programmer." />
<title>Fernando Garibay - Music</title>
<link rel="icon" type="image/png" href="http://www.fernandogaribay.com/favicon.ico" />
<link href="../styles/fernando.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="https://www.google.com/jsapi?key=ABQIAAAAqfg-jHFfaMB9PWES0K_8ChTCwkclEZER8BG2IP57SKkFV1O9hxSZkzKYPDs-3mbhEluKXjbKUAB7sQ"></script>
<script type="text/javascript">
google.load("jquery", "1.5.1");
google.load("jqueryui", "1.8.8");
</script>
<script type="text/javascript" src="../scripts/fernando.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<!--Copyright 2011, Fernando Garibay, Inc-->
<!--Developed by Minimal +-->
</head>
<body onload="message()">
JavaScript (the function that works on jsFiddle, but not in a live page)
$(function() {
$(".playback").click(function(e) {
e.preventDefault();
var song = $(this).next('audio').get(0);
if (song.paused)
song.play();
else
song.pause();
});
});
I see two JavaScript errors on your live page (in both Chrome and Firefox):
Uncaught TypeError: Object [object Object] has no method 'fancybox'
Uncaught ReferenceError: message is not defined
You reference fancybox() in fernando.js, and message in the <body onload="message()">. Those errors are most likely stopping your audio control code from running.
The URL is http://fiddle.jshell.net/66FwR/3/show/ look at that.
It includes jQuery UI too. You could copy the source and use that.