When I execute the below test HTML page in Chrome, I see the following in the debug console:
Has parent? true
Has parent? false
Am I right in assuming that this a Chrome bug (it doesn't happen in other browsers), or is Chrome within its right to do this for some reason? It resulted in a bug in one of my web apps and I finally isolated this snippet to repro the core issue.
Here is the test page:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body class="">
<script>
function testDoodle() {
var testParentEl = document.createElement('div');
var testChildEl = testParentEl.appendChild(document.createElement('div'));
document.body.innerHTML+=('Has parent? ' + !!testChildEl.parentNode+'<br>');
console.log('Has parent? ' + !!testChildEl.parentNode);
setTimeout(function() {
document.body.innerHTML+=('Has parent? ' + !!testChildEl.parentNode+'<br>');
console.log('Has parent? ' + !!testChildEl.parentNode);
},
2000);
return;
}
testDoodle();
</script>
</body>
</html>
EDIT: I should have mentioned that I'm testing on Windows 7 with Chrome 49.0.2623.87 m (64-bit). Was also able to repro on OSX 10.11.2 with Chrome 49.
Also, I should mention that sometimes it displays true/true and sometimes true/false. You might have to reload the page a few times to witness the issue. I'm not sure, but it's possible that the debug tools (console) need to be open as well.
Thanks much.
My guess is that testChildEl.parentNode does not reference testParentEl strongly, so it's garbage collected.
Both referencing testParentEl inside the timeout and adding a strong reference to testParentEl on testChildEl fix the problem for me:
(function testDoodle() {
var testParentEl = document.createElement('div');
var testChildEl = testParentEl.appendChild(document.createElement('div'));
setTimeout(function() {
testParentEl; // Prevents it from being garbage collected
document.write('Has parent? ' + !!testChildEl.parentNode);
}, 100);
})();
(function testDoodle() {
var testParentEl = document.createElement('div');
var testChildEl = testParentEl.appendChild(document.createElement('div'));
testChildEl.strongParent = testParentEl; // Prevents garbage collection
setTimeout(function() {
document.write('Has parent? ' + !!testChildEl.parentNode);
}, 100);
})();
I believe that this is finally fixed by Chrome v50 (or at least I haven't been able to repro since updating).
Related
This question already has answers here:
setTimeout Internet Explorer
(7 answers)
Closed 5 years ago.
I have the following web page:
<html>
<head>
</head>
<body>
<h1>Wait until closed</h1>
<script>
function wait(popup){
if (!popup.closed){
setTimeout(wait,1000,popup);
} else {
alert('closed');
}
}
var popup = window.open("http://www.google.com", '', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=yes, width=1000 , height=800, top=' + screen.top + ', left=' + screen.left);
wait(popup);
</script>
</body>
</html>
When I open it with Chrome or Firefox, I see the message 'closed' after I close the popup. In IE11 however nothing happens. What is the explanation of this difference in behaviour? (i.e. which part of the standards IE11 does not adhere to, or interpret differently in this case, if at all?)
EDIT: reading the suggested answers, I tried to change setTimeout(wait,1000,popup) to setTimeout(function() {wait(popup);},1000), like this:
<html>
<head>
</head>
<body>
<h1>Wait until closed</h1>
<script>
function wait(popup){
if (!popup.closed){
setTimeout( function() {
wait(popup);
}, 1000 );
} else {
alert('closed');
}
}
var popup = window.open("http://www.google.com", '', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=yes, width=1000 , height=800, top=' + screen.top + ', left=' + screen.left);
wait(popup);
</script>
</body>
</html>
but this does not work either.
EDIT: The comments indicate that this is a duplicate, but since trying to change the code according to the suggested answers did not work for me until now, I modify the question by asking to change the above code so that it works in IE11 (hope that this is allowed by SO rules). The code shown does not work.
This one was kind of bugging me, so I tried it in on a local file and got the same behavior. window.open returning null in both IE and Edge. Apparently if protected mode is enabled, window.open will return null in both IE and Edge.
https://msdn.microsoft.com/en-us/library/Bb250462.aspx
I'm not sure how to work around it. Maybe a closeable frame?
I have an iframe which needs to copy a script to the parent and execute a function in the parent:
<!doctype html>
<html lang="en">
<head>
</head>
<body>
<script id="myscript">
function foo() { alert('foo'); }
</script>
<script>
(function () {
var script = document.getElementById('myscript');
parent.document.head.appendChild(script);
// call function in parent
parent.foo();
})();
</script>
</body>
</html>
I get undefined is not a function. Why is that function not defined in the parent?
Bear in mind that you will be subject to cross-origin security and other inter-frame restrictions, which shouldn't be an issue if you host both frames from the same domain, but will block this pretty effectively otherwise.
Getting an element from the child frame and appending it to the parent probably won't work, and is definitely overly complex. I would suggest creating a new script element on the parent and simply copying the content. Something like:
(function () {
var pdoc = parent.document;
var dest = pdoc.head;
var text = document.getElementById("myscript").textContent;
var pscr = pdoc.createElement("script");
pscr.textContent = text;
dest.appendChild(pscr);
parent.foo();
})();
This is fairly difficult to make a good example for, as JSFiddle and the like serve their frames from different origins, so I haven't tested it thoroughly. Getting the script content this way definitely works, and creating the element certainly should. The closest I could come while testing was to rename the function and use the current frame:
(function() {
var pdoc = self.document;
var dest = pdoc.head;
var text = document.getElementById("myscript").textContent.replace("foo", "bar");
var pscr = pdoc.createElement("script");
pscr.textContent = text;
dest.appendChild(pscr);
self.bar();
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If you want this to be a more portable solution, you may also look into using the onMessage handler in the script and firing a message from the child (message-passing is somewhat more complex, but often more maintainable, than inter-frame calls).
I've been experiencing an odd problem with IE10 when redirecting the page on an 'oninput' event (with no equivalent issue when using Chrome). I've produced the most pared-down version of the code that still exhibits the problem, as follows:
<html>
<head>
<script type="text/javascript">
function onChangeInputText()
{
window.location.href = "oninput_problem.html"; // Back to this page.
}
</script>
</head>
<body>
<input type="text"
oninput="onChangeInputText()"
value="£"
/>
</body>
</html>
On my Windows 7 PC using IE10, this code when browsed to (either by double clicking or via Apache) repeatedly redirects as if the act of initialising the value of the input text box itself is generating an immediate 'oninput' event. However, when I change the initial input text box value from the '£' symbol to a letter 'A', the repeated redirection doesn't occur.
I first noticed this problem as part of a project I'm working on. In that case, the user's input should cause a delayed page refresh, which began repeatedly redirecting when I entered a '£' symbol. As I say, the above code is the most pared-down version I produced in trying to track what was causing the issue.
Does anyone else experience this using IE10? If so, can anyone explain why IE10 is behaving this way?
I've found the following that appears to indicate that this may be a bug in IE10:
social.msdn.microsoft.com: Event oninput triggered on page load
Also, there's a follow-up bug report (within the page linked to above):
connect.microsoft.com: onInput event fires on loading the page when input #value is non-ASCII
EDITED TO ADD: At the bottom of the page pointed to by the second link, there's what would seem to be an unhelpful reply from Microsoft stating that they are unable to reproduce the bug described, so it may be a while before the issue is fixed...
There's anoter bug report which is still open :
http://connect.microsoft.com/IE/feedback/de...
For anyone who might encounter this, you can use this "class" as an alternative to the onInput event.
const getFieldWatcherInstance = (function(watchedElement, onElementValueChange){
let intervalReference = null;
let lastValue = null;
if(!watchedElement instanceof Element) return new Error('watchedElement is not an HTML Element');
if(typeof onElementValueChange !== 'function') return new Error('onElementValueChange is not a function');
return {
toggleFieldWatching : function(){
if(intervalReference){
clearInterval(intervalReference);
intervalReference = null;
}
else{
intervalReference = setInterval(function(){
const currentValue = watchedElement.value;
if(lastValue !== currentValue){
onElementValueChange(currentValue);
lastValue = currentValue;
}
}, 100);
}
}
};
});
Set it up like this:
const myInputChangeWatcher = getFieldWatcherInstance(<**insert real element reference here**>, function(newValue){
console.log('The new value is: ' + newValue);
});
call myInputChangeWatcher.toggleFieldWatching() in the onfocus and onblur events of the input
On a website I'm designing a user searches for hotels in a city, and results are returned as xml then formatted through ajax/javascript/jquery.
The results are displayed almost immediately in Chrome or FF, but in Internet Explorer (I've tried ie6 and ie9) the results take almost a minute to be displayed.
Running the developer tools in IE states that 99% of execution time is spent in function "getElementsByTagName" which is called almost 200,000 times, however I'm unaware of how to fix this if it is the issue.
The page in question is beta.hotelsweep.com and the function being called on search is:
//summarized version of the function
$.get(url, function (xmlResponse) {
$('#results').empty();
var exception = $("Exception", xmlResponse);
if (exception.size() > 0) {
var error = "<h2>We were unable to complete your request</h2>";
$('#results').html(error);
} else {
$('#numResults').html($("resultsNumber", xmlResponse).text() + " hotels found <br>");
var resultsHtml = "<div id='results_list'>";
//set googlem map to center
map.setCenter(new GLatLng($("avgLat", xmlResponse).text(), $("avgLong", xmlResponse).text()), 9);
// Loop through response, creating <li> for each hotel
$("Hotel", xmlResponse).each(function () {
var bookLink = $('affiliateLink', this).text();
var address = $('fulladdress', this).text();
var stars = $('stars', this).text();
resultsHtml += 'Hotel Stars: ' + stars;
});
//put html into results div
$('#results').html(resultsHtml);
}
});
You can't really fix this issue. getElementsByTagName isn't indexed in older versions of IE. You can use element id lookups instead (avoid $("Exception"), $("avgLat"), etc).
If that's not feasible, you can add a script on the server to render the results to HTML.
It turns out the issue was something to do with the document mode. In quirk mode, the javascrit wasn't even fully executing.
Adding this to the top:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
or
<meta http-equiv="X-UA-Compatible" content="IE=9" />
Made Internet Explorer execute as expected. I don't fully understand what is happening, but if you find your javascript executing incorrectly only in IE it could be to do with the document mode.
So I have the following code, which should append 'true' to the div "test" every 25ms as long as key 68 (the d key) is being pressed, right?
<html>
<body>
<div id="test"></div>
<script type="text/javascript">
var key=false;
var keyDown=function(e) {
if (e.keyCode==68) {
key=true;
}
}
var keyUp=function(e) {
if (e.keyCode==68) {
key=false;
}
}
document.onkeydown=keyDown;
document.onkeyup=keyUp;
var run=function() {
document.getElementById('test').appendChild(document.createTextNode(key+'\n'));
t = setTimeout('run()', 25);
}
var t = setTimeout('run()', 25);
</script>
</body>
</html>
Save the code, load it in a browser and hold down on the d key. If I'm not crazy, you'll see that it occasionally appends 'false' even though the d key was never released. (I've tried this in FF and Chrome in Linux and Vista). Anybody happen to know why, or have a workaround?
Edit: It seems to behave as expected in FF running in OS X.
I just tried it in IE7. After changing "e.keyCode" to "event.keyCode", it worked just as you expected.
Have you actually tried the code you pasted here, or are you working with other code that may have a bug in it?
Edit
I just ran this in Chrome. Again, it behaves as expected.
Are you using a wireless keyboard that could be susceptible to interference or battery weakness that wouldn't affect normal keyboard use, but becomes visible in this test?