'Date' is undefined in IE9 in javascript loaded by FacePile - javascript

I'm currently getting an error within Facebook's FacePile code, and I'm baffled by the cause.
facepile.php loads a script which, among other things, has these lines (when pretty-printed):
...
o = document.createElement('script');
o.src = l[n];
o.async = true;
o.onload = h;
o.onreadystatechange = function() {
if (o.readyState in c) {
h();
o.onreadystatechange = null;
}
};
d++;
a.appendChild(o);
...
(a == document.body, d++ is irrelevant here)
This code loads a script with src = http://static.ak.fbcdn.net/rsrc.php/v1/yW/r/pmR8u_Z_9_0.js or something equally cryptic (the filename changes occasionally).
In that script, there are these lines at the very top (also when pretty-printed):
/*1331654128,176820664*/
if (window.CavalryLogger) {
CavalryLogger.start_js(["\/8f24"]);
}
window.__DEV__ = window.__DEV__ || 0;
if (!window.skipDomainLower && document.domain.toLowerCase().match(/(^|\.)facebook\..*/))
document.domain = window.location.hostname.replace(/^.*(facebook\..*)$/i, '$1');
function bagofholding() {
}
function bagof(a) {
return function() {
return a;
};
}
if (!Date.now)
Date.now = function now() {
return new Date().getTime();
};
if (!Array.isArray)
Array.isArray = function(a) {
return Object.prototype.toString.call(a) == '[object Array]';
};
...
And I'm getting an error which says "SCRIPT5009: 'Date' is undefined", right at the if (!Date.now) portion. Debugging near that point reveals that Date, Array, Object, Function, etc are all undefined.
Er... how? window exists, as does document (though document.body is null) and a handful of others, but plenty of pre-defined objects aren't. Earlier versions of IE don't seem to have this problem, nor do any other browsers, but multiple machines running IE9 (including a clean VM) all have the same issue.
I doubt I can do anything about it, but I'm very curious how this is happening / what the underlying problem is. Does anyone know, or can they point me to something that might help?
-- edit:
Prior to posting this question, I had found this site: http://www.guypo.com/technical/ies-premature-execution-problem/
While it seemed (and still does) like it might be the source of the problem, I can't replicate it under any smaller circumstances. All combinations I've tried still have Date, etc defined ; which isn't too surprising, as otherwise I'm sure others would be seeing many more problems with IE.

If you step through with a javascript debugger at the first point any JS gets run. At the same time add a watch for Date/Array etc. and note when it goes to null. Might be slow and laborious but I can't see why it wouldn't work.

You may want to try adding the script in a document.ready function. In other words, insure that the FB script is processed only after the DOM is ready. But, based on the link you give to Guy's Pod (great article, by the way), it seems you're right in the assertion that IE is downloading and executing the script pre-maturely (hence my suggestion to add a wrapper so that it only executes after the DOM ready event). IE9 is probably sandboxing the executing script (outside the document/window scope).

Related

Google Scripts/Basic JavaScript - Issue fixed by debugger

I'm working on a Google Scripts add on for Google Sheets, but I'm trying to get the script working before I actually set it up on the sheet. The code below works fine if I set a breakpoint somewhere in the extractNumbers function. If I just execute the code without breakpoints, I get an error:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
Here's the code:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
function phoneCheck(newCell,newHome,oldCell,oldHome) {
Logger.clear();
var newCell = extractNumbers(newCell);
var oldCell = extractNumbers(oldCell);
var newHome = extractNumbers(newHome);
var oldHome = extractNumbers(oldHome);
if (newCell === oldCell) {
return newCell;
exit;
} else if (newCell === oldHome && newHome === oldCell) {
return oldCell;
exit;
}
if (newCell === '' && oldCell !== '' ) {
return oldCell;
exit;
}
if (newCell !== oldCell && newCell !== oldHome) {
return newCell;
exit;
}
return "No value found";
exit;
}
function extractNumbers(input) {
Logger.log(input);
var str = input;
return str.replace( /\D+/g, '');
}
Now I realize my if/then logic is more than a bit inelegant, but for my purposes, quick and dirty is fine. I just need it to run.
ALSO, I have read of other novice JavaScript programmers having similar issues related to the sequence of code execution. If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too. Thanks!
EDIT: I put my code into a new fiddle and it works fine, but it continues to fail in Google Scripts editor unless running in debug mode with a breakpoint. The problem seems to be that the function parameters aren't available to the function unless there is a breakpoint. Anyone have access to Google Scripts that can try my updated code from https://jsfiddle.net/hrzqg64L/ ?
None of the suggestions got to the root of your problem - and neither did your answer, although you've avoided the problem by putting an enclosure around everything.
There's no AJAX, no asynchronous behavior - it's simpler than that. "Shadowing of parameters" is likewise a red herring. Bad coding practice, yes - but not a factor here.
If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too.
Sorry - no such thing. I can explain what's going on, but can't guarantee it will be accessible to novices.
The exception
Let's just clarify what causes the exception, or thrown error, that you've observed.
As written, extractNumbers() will throw an exception if it has a null parameter (or any non-string parameter) passed to it. If you choose to extractNumbers() then hit "run", you'll get:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
That is telling you that on line 36, which is return str.replace( /\D+/g, '');, the variable str contains an object that is undefined (...and has no replace() method).
For bullet-proof code, you would check your parameter(s) to ensure they are valid, and handle them appropriately. Sometimes that would be with a valid default, and other times you might return an error or throw an exception that is more explicit about the parameter problems.
Running code in Google's debugger
The only way to run code in Google's Debugger is to select a function, then choose "run" or "debug". Assuming you posted all your code, you had just two functions to choose from:
phoneCheck()
extractNumbers()
Whenever Google Apps Script runs any part of a script, the entire script is loaded and scanned to find all symbols & check syntax. The scope of all symbols is noted as well, and so are any dependencies between functions and global symbols (symbols outside of any closure, or block of code).
That takes some time. To speed things up when asked to execute a specific function, the global symbols are only evaluated if they are a dependency for the requested function or the functions it may call. There is another condition that will trigger evaluation of global symbols, and that is if there is a possibility that the debugger may need to stop and display values.
When this happens, any code that is outside a closure (outside a function, for example) will be executed. This is what you observed when you set breakpoints.
Why did it work when breakpoints were set?
As explained, just having a breakpoint set triggers evaluation of global symbols.
You start this script with a few lines of code that are not in any closure:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
It is that code which makes the only proper invocation of phoneCheck() with parameters. Because myVar is evaluated, phoneCheck() gets called with parameters, and in turn calls extractNumbers() with a defined parameter.
Unfortunately, because of the way the debugger works, you cannot choose to run that code yourself. You need to rely on these side-effect behaviors.
How to fix this?
Simple. Don't rely on global code to invoke functions under test. Instead, write an explicit test function, and call that.
function test_phoneCheck() {
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
}
Finally found the issue, but I don't fully understand it.
This question got me thinking about scope and how it might be different in the Google Script environment. I figured a simple workaround would be to enclose the entire script in its own void function, and it worked! Also, I simplified the script quite a bit with an array:
function init () {
var numberArray = ["a3", "a2", "o3", "o10"];
var myVar = phoneCheck(numberArray);
Logger.log(myVar);
function phoneCheck(myArray) {
var phoneString = '';
Logger.clear();
var arrayLength = myArray.length;
for (i = 0; i < arrayLength; i++) {
phoneString += myArray[i].replace(/\D+/g, '');
}
return phoneString;
}
}
Also, I realize the functionality of this script is different than the original, but I was really just trying to solve this problem. Now that I have, I can finish the script properly.
Thanks for all the suggestions, everyone! I learned a lot of good things, even though they turned out not to be the answer.

Enable/Disable debug code dynamically

I'm writing a decent sized JavaScript animation library, that I would like to include debugging code in. I could easily do a check :
if(myLib.debugger){
console.warn('warning message');
}
However if this runs a couple thousand times a second, it would eventually cause performance issues. Add in a few more checks throughout the code and the effect will be even more noticeable.
What I'm wondering is if it would be possible to check onload if the debugger should be enabled, and if so... turn something like this:
//debugger if(!this.name) console.warn('No name provided');
into:
if(!this.name) console.warn('No name provided');
Leaving the code commented if its not enabled, and uncommenting it if it is, thus removing any possible performance issues. Could this be done somehow with a regular expression on the entire script if loaded in through ajax? I'm trying to avoid the need for 2 versions of the same code, lib.dbug.js and a lib.js.
Cross browser compatibility is not of great importance for this (I'm really only worried about new browsers), I see it as nice to have item. If its possible however, it would be a great thing to have.
Any insight would be greatly appreciated.
The simplest way to do this would be to check if the debugger should be disabled and if so, replace it with a mock object that does nothing at the very start of your script:
if (!myLib.debugger) {
window.console = (function () {
var newConsole = {};
var key;
for (key in window.console) {
if (typeof window.console[key] === 'function') {
newConsole[key] = function () {};
}
}
return newConsole;
}());
}
The overhead of this approach should be negligible.
If this is a JavaScript library... then I'd expect as a 3rd party developer that I could download/use 2 versions. The production version (no debug, AND minimized). If I wanted to debug, I would point to the debug version of the library instead.
e.g.
<script src="foo-lib-min.js"></script>
<!-- swap to this for debugging <script src="foo-lib-full.js"></script>-->

How to only wait for document.readyState in IE and fire instantly for all other browsers?

I have written a CSS and Javascript lazyloader to dynamically load resources for seperate pagelets (in the way that Facebook renders a page with it's BigPipe technology).
In short an HTML frame is rendered first, then separate parts of the page are all generated asynchronously by the server. When each pagelet arrives the pagelets css is loaded first, then its innerHTML is set, then finally we load any required javascript for this pagelet and initialise it.
Everything works perfectly and perceived load time is pretty much instantaneous for any given page.
However in IE, I occasional I get Method does not support method or property when initialising the scripts.
I have solved this by checking for document.readyState before loading the scripts.
Now this isn't a huge issue but it adds on average 170ms to a pageload in chrome or firefox. Which is not needed.
function loadScripts(init){
// ensure document readystate is complete before loading scripts
if( doc.readyState !== 'complete'){
setTimeout(function(){
loadScripts(init);
}, 1 );
}
else{
complete++;
if(complete == instance.length){
var scripts = checkJS(javascript);
if(scripts.length) {
LazyLoad.js(scripts, function(){
runPageletScript();
for (var i = 0; i < scripts.length; ++i) {
TC.loadedJS.push(scripts[i]);
}
});
}
else{
runPageletScript();
}
}
}
}
What I am looking for is a modification to this script which will only implement the 'wait' in IE, if it is any other browser it will just fire straight away. I cannot use a jQuery utility like $.Browser and need it to be the tiniest possible method. I hate to use any form of browser detection but it appears as though its my only solution. That said if anyone can come up with another way, that would be fantastic.
Any suggestions would be gratefully received.
You could use JScript conditional compilation, which is only available in IE browsers (up to IE10).
Because it's a comment, it's best to place it inside new Function as minifiers might remove it, changing your code. Though in general you should avoid using new Function, in this case there's not really any other way to prevent minifiers from removing it.
Example:
var isIE = !(new Function('return 1//#cc_on &0')());
However, it seems that your main issue is that the DOM hasn't loaded yet -- make sure that it has loaded before running any loader using the DOMContentLoaded event (IE9+):
document.addEventListener('DOMContentLoaded', function () {
// perform logic here
});
Here is just another solution as the solution from Qantas might not always work. For instance on UMTS connections it could happen that providers remove comments to save bandwith (maybe they preserve conditional comments):
if(navigator.appName == 'Microsoft Internet Explorer'
&& doc.readyState !== 'complete'){
...
}

Issue with retrieving object data on IE 8 on Windows XP or 2003

This is an interesting problem that I am facing with JavaScript and IE8 on Windows XP and Windows 2003. I create an object on the page and then retrive information about that object (for example, its version). When trying to get the version, I am running this code:
var myObject = document.getElementById(objectId);
console.log(myObject.version);
What is interesting is that this code works on every single browser except IE8 on Windows XP and 2003. I've done some debugging and this is where things get interesting.
myObject is not null but myObject.version is undefined. So what I did is I added an alert in between so the code is now as follows:
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
The alert results in "undefined", however, the console.log is now resulting in the actual version. If I add an alert before this alert of anything (let's say alert("something")) then the second alert has the actual version now. I am assuming this is a timing issue (for some reason the object needs sometime to be able to provide the data stored in it?) but I am not sure what kind of timing issue this is or how to approach it.
Sorry for the long description but any help is appreciated.
document.getElementById doesn't return an object. It returns a DOM element. So, you expect to see a .version property in a DOM element, which by the official W3C specification is missing (or at least I don't know about this).
I'm not sure what you are expecting to see in .version, but if it is something custom then you should create a custom object like that:
var o = { version: "..." }
console.log(o);
You said that this may be a time issue. If that's true then I'll suggest to try to access the .version property after the DOM is fully loaded. You can use jQuery for the purpose:
$(document).ready(function() {
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
});
You can add a setTimeout in your function till the .version property is there.
var f = function(callback) {
var check = function() {
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
if(typeof myObject.version !== "undefined") {
callback(myObject.version);
} else {
setTimeout(check, 1000);
}
}
setTimeout(check, 1000);
}
What happens if you put the <script>...</script> tag with the js code at the end of the html file? In my opinion, the code is executed when the DOM is not ready. If you put it in the end, then it will be executed after it's loaded.

Is window.document ever null or undefined?

I've been doing some research on the window.document object in order to make sure one of my JavaScript solutions is reliable. Is there ever a case when the window.document object is null or undefined?
For the sake of discussion here's a non-relevant example piece of code. Are there any situations in which this piece of code will fail (aka, throw an exception)?
$(document).ready(function() {
var PageLoaded = (window.document.readyState === "complete");
});
Is there ever a case when the window.document object is null or undefined?
Yes, for JavaScript code that isn't in a document (e.g. node.js). But such code may not have a window object either (though it will have a global object).
For code in HTML documents in user agents compliant with the W3C DOM, no.
> Are there any situations in which this piece of code will fail (i.e. throw
> an exception)?
>
> [snip jQuery code]
It will fail where:
the jQuery ready function fails (likely in at least some browsers, though not the ones in popular use for desktop and some mobile devices),
there is no window object, or
there is no window.document object
To be confident of code working in a variety of hosts, you can do something like:
if (typeof window != 'undefined' && window.document &&
window.document.readyState == whatever) {
// do stuff
}
which isn't much extra to write, and likely only needs to be done once.
Alternatives:
(function (global) {
var window = global;
if (window.document && window.document.readyState == whatever) {
// do stuff
}
}(this));
and
(function (global) {
var window = global;
function checkState() {
if (window.document && window.document.readyState) {
alert(window.document.readyState);
} else {
// analyse environment
}
}
// trivial use for demonstration
checkState();
setTimeout(checkState, 1000);
}(this));
I think document is always defined, cause all that browser shows you is a html-document, even site is not available . More, document is readonly property
window.document = null;
console.log(window.document); //Document some.html#
Ignoring the fact that Javascript runs other places besides web browsers/user-agents, your pageLoaded test may fail on iframes (untested, but I know they get weird).
There may also be some question about what does "page loaded" mean. Are you trying to see if the DOM has been rendered and the elements are ready to be manipulated? Or are you checking to see if the page load is indeed complete, which includes having all of the other elements, such as graphics, loaded as well.
This discussion may be useful:
How to check if DOM is ready without a framework?
Because your javascript code must be written in a html document,so your code coudn't be executed out of document,in other word,no document,no javascript.

Categories

Resources