Can I stop Chrome from eating my global property? - javascript

Chrome on iOS appears to create an XMLHttpRequest object when you include an external JavaScript file. It seems to assign this object to a global variable with the identifier a, overwriting anything you may have already had in there.
Test case:
HTML file (test.html):
<!-- ... -->
<script>
var a = 1; // Value is not important for this demonstration
</script>
<script src="test.js"></script>
<!-- ... -->
External JavaScript file (test.js):
setTimeout(function () {
document.write(a); // [object XMLHttpRequest]
a.onreadystatechange = function () {
document.write(a.readyState); // Alternates between "1" and "4"
};
}, 100);
The XMLHttpRequest appears to repeatedly make a request (to somewhere... routing the device connection through a proxy and monitoring requests doesn't show up anything) and the onreadystatechange event handler is repeatedly executed.
Some more observations:
This only seems to happen some time after page load (hence the setTimeout)
When it does happen, there is also a window.__gchrome_CachedRequest property
__gchrome_CachedRequest === a
It doesn't seem to happen in older versions of iOS Chrome (not sure which version it first occurs in though)
Has anyone come across this before? Is there a way I can stop it from happening (Note... I cannot rename a)? If anyone knows why it does this I would love to find out.
Update
I've just noticed that this actually happens with inline scripts too, not just when you include an external script. I didn't notice this initially because I didn't have the setTimeout call in there. So it looks like it actually just always happens some time after page load.

From the discussion we had in comments, it looks like Chrome is using a with statement to layer some of its own stuff over the top of window properties. It probably does this because those properties would not normally be overwritable. The delay is most likely down to how soon Chrome can inject its own script into the UIWebView (browsers on iOS are forced to use the underlying UIWebView object rather than their own engines) after a page starts loading.
If all this speculation is actually true, then there's simple solution, other than to access window.a instead of a or take the power back and use your own with statement:
with (window)
eval(myScript);
Hardly a solution anyone would relish implementing, but might be your only option.

Related

Can I resolve this "Cannot read property 'xxxx' of undefined" issue by using keyword 'defer'?

In my web app I inject some user specific data into the html page.
It looks like this in the page source
<body>
<script>
var userData = {};
window.GLOBAL = {
userData: userData
};
userData.user = {'user_hash': 12478999584505 };
</script>
<script src="/static/scripts/myapp.js"> </script>
Inside myapp.js I retrieve the user_hash and call an initialisation function:
init(window.userData.user.user_hash);
A few users experience this problem spuriously:
Cannot read property 'user_hash' of undefined
It turns out it is very hard for me to pinpoint the exact cause of the problem. This error never happen to me in either production or development environment. There is also no error on the server side that indicates the user_hash generation has failed. I have tried to reproduce this error by throttling network speed in Chrome via Dev Console etc but I haven't been able to trigger this error yet.
On the user side, the platforms vary from mobile devices (could be running the latest version of iOS or andriod) to desktop, and different browsers (chrome, firefox or safari). My point is there is no clear pattern I can pin it down to a particular platform or brower version.
I speculate that the exception happens if /static/scripts/myapp.js is loaded and executed before window.GLOBAL is properly initialised, this exception will be fired.
I am thinking of adding defer keyword to the myapp.js script tag, based on this answer.
My questions are:
1) Is there any issue with my current HTML markup? (the two script tags)
2) My hypothesis is basically that these two script tags may have some racing condition between them. Does it stand?
3) Can adding defer attribute to the second script tag potentially fix this issue if answer to question 2 is yes?
4) If answer to question 3 is no, what else I can try?
1) Is there any issue with my current HTML markup? (the two script tags)
No there is no issue with HTML markup.
2) My hypothesis is basically that these two script tags may have some racing condition between them. Does it stand?
I did not get this question perfectly. Probably you should show your myapp code here
3) Can be adding defer attribute to the second script tag potentially fix this issue if answer to question 2 is yes?
No. JavaScript is always synchronous and single-threaded. If you're executing a JavaScript block of code on a page then no other JavaScript on that page will currently be executed. JavaScript is only asynchronous in the sense that it can make, for example, Ajax calls. and Defer instructs the contents of the script tag to not execute until the page has loaded.
4) If the answer to question 3 is no, what else I can try?
You don't require to use GLOBAL here because when you initialize variable with var on top of the script then it may automatically consider in a global scope. JavaScript has two scopes: global and local. A variable that is declared outside a function definition is a global variable, and its value is accessible and modifiable throughout your program. A variable that is declared inside a function definition is local, and second thing window object represents. the browser's window. All global JavaScript objects, functions, and variables automatically become members of the window object.
Here following code may fulfil your requirement
var userData = {
userData: userData
};
userData.user = {'user_hash': 12478999584505 };
console.log(userData.user.user_hash);
Here is also link of working fiddle: https://jsfiddle.net/dipakchavda2912/eohb0npr/

Expose variable to the devtools console without making it global on window

Is it possible to make a variable easily accessible by the debug console without actually making it global? For example, something like this in the code:
console.$ = jQuery
And then in the console, I'd like this to work:
$('#foo')
Not while the page isn't paused at a breakpoint, no. But when the page is paused at a breakpoint, the console has access to all variables that are in-scope at the point where it's stopped.
Of course, your console.$ = jQuery example does make it possible to do
console.$("#foo")
...in the console.
Side note: console.$ = jQuery and $("#foo") aren't great examples, as jQuery is almost always global, and even if you don't have jQuery loaded on your page at all, Chrome provides its own $ function in the console, and I think at least one other browser does as well...

IE 11 Will not load systemjs

I am working with SystemJS and I have a pseudo-bootstrapper file that I use to check to make sure certain conditions are met before the loading of the main scripts to execute the page load. Here is a snippet of that code.
var obj = document.createElement('script');
obj.src = 'jspm_packages/system.js';
document.body.appendChild(obj);
This code does NOT execute the script, yet it does load it with a 200 code as evidenced by the network tab within the IE dev tools. There should be a global object "System" created, but it does not exist. Looking through the DOM, the object is properly created and appended to the body.
Does anyone know if this is strictly an issue with IE and SystemJS? I have no idea what's going on. I'm pulling my hair out, as per usual with the demon that is IE. I should note that every other browser works as expected, providing the "System" global variable.
EDIT Further testing has assured that this is not an issue with appendChild, as other scripts using the same method, execute on load just fine.
Reading this article tells us that your script may not run in IE11. The line in particular which is of interest is:
"Script elements with external resources should no longer execute during appendChild."
This appears to be what's happening.
EDIT: An alternate approach could be taken.
It would be a good idea to do condition checks on the server side before sending the response if you want to change page loading at the system.js level. If that is not possible then I'd suggest doing a redirect after the condition checks instead of appendChild.
The answer is that IE versions < Edge do not support promises. I needed a polyfill for IE 11.

Edit JavaScript code in chrome and reload page

Very often I hack and play with the JavaScript code on some website. Many times JavaScript code is secured in a function:
(function(){
var = ...
...
}());
and I cannot access the object defined in that scope.
Moreover such code is only executed once, when the page loads, thus modifying it with the chromium/google-chrome developer console (Sources toool) is useless.
Is there any simple way to live-edit some JavaScript code in a page and reload the page so that it runs the modified code?
Have a look at using something like Tampermonkey https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en
the Chrome equivalent of Firefox's Greasemonkey
EDIT: you could use this in combination with adblock to disable the loading of the script you are targeting: https://stackoverflow.com/questions/13919183/how-to-turn-off-one-javascript-or-disable-it-under-chrome
I wouldn't call it simple, but something like Intercept Proxy might be able to do it -- replacing one file with another.
I found a way to achieve what I needed.
Using Chromium's debugger I can set a breakpoint on any statement of the source code.
Once that statement is executed, the code suspends and Chromium's console gives me access to whatever is in the stack of the current function.

IE 7 & 8 javascript file undesirably caching with require.js

I have a page javascript page.js being loaded with require.js. The call to the page.js is placed on the bottom of the page after the calls to require.js and is as follows:
<script>
require(["page"]);
</script>
Functions inside the page.js simply do not execute each time the page is accessed.
To be clear, an alert('hello'); in the middle of page.js will be alerted most but not all of the times. I'm pretty sure this is not an existing IE issue, and that a simple alert will always execute provided there are no other JS errors.
95% of the time the page and it's corresponding functions execute, about 5% of the time the IE browsers are not reexecuting the contents of the page.js.
I don't think this is an inherent IE issue, but rather require.js is stumbling over related aggressive caching issues found in IE.
Edits:
Just to clarify, the page.js file is visible in the f12 dom load when the error occurs. The page is properly cached. The issue is that the cached code file is not re run!
For instance the alert in this file is not executed!
I'm not sure about the internals of require.js but I suppose they do xhr for the resources and eval it. It seems the xhr completes and loads into the dom, but the eval isn't working correctly. (This is of course speculation, as I don't know enough require.js internals).
The only way i know to prevent caching your js files is to add a random string to the end :
example :
<script src="http://www.mydomaine.com/myjsfile.js?t=123456"></script>
generate the "t" parameter content randomly using an md5 hash or wathever, this makes browsers believe that it's a different file each time.
There problem may not be due to caching. Caching is basically controlled on the server-side, so if you do not want a file cached, you have the server setting the cache-control headers to do that. Caching does not affect if a javascript file is "executed" or not, it only affects where the browser gets data from when trying resolve a given resource. Normally, you want .js files to be cached for performance reasons.
In your case, caching may not be the real problem. When using dynamic javascript source loaders (libraries like dojo support this), it may best that the file you load is wrapped in the following:
(function(){
// Main code here...
})();
This defines an anonymous function, and then executes it right away. This gives the following advantages:
Creates a closure so you can declare variables that are only visible in the scope of your file.
Ensure that any direct executable statements are executed.
Note, I'm not familar with require.js, so there is a possibility it can play a role in your problem. Also, you did not provide the file you are loading via require, which it may have a bug that is causing the inconsistency you are encountering.
Conclusion:
IE (where it was mostly occurring) was kind of swallowing up the error, when we were able to reproduce it in Chrome, we found an error indicating that one of our global funcs wasn't yet loaded because the global funcs file wasn't added to the require list. Unfortunately, we're not using require.js's compile + optimization which may or may not have barfed without an IMPLICIT listing of the globals.js as a dependency.
I guess the take home is make sure any functions called are themselves defined in a dependency implicitly listed in the require block!

Categories

Resources