I've been spending some thinking time recently on how to best handle resource failure for a page.
Of course with JavaScript files there isn't much 'clever' stuff that you can do. If you're loading from a CDN we can do something like this (taken from the HTML5 Boilerplate project):
<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="local/jquery-1.6.1.min.js">\x3C/script>')</script>
However I haven't seen much documented on CSS failure.
If your page is a blog post or something similar then best practice would be to make sure your markup is good, so that the un-formatted version is still a very much readable, if only a little boring, document.
But what if you don't want to fall back to Lynx style? There may be a good reason; for example your application is complicated and is very much dependant on your layout. In which case, showing the page with no stylesheet is probably worse for user experience than not showing it at all.
Therefore, I wondered if a solution such as this would work - and if any of you are using it (or something similar)?
Add a helper class at the end of your CSS file #test { line-height: 1; }
Add this JavaScript at the end of your page
var el = document.createElement('div');
el.setAttribute('id', 'test');
document.body.appendChild(el);
var o = (el.currentStyle) ? el.currentStyle['line-height'] :
(window.getComputedStyle) ? document.defaultView.getComputedStyle(el, null).getPropertyValue('line-height') : null;
if (o !== '1px') {
document.body.innerHTML = '<p>Resources failed to load, a prettier message should go here</p>';
}
See this JS Fiddle for it all together.
Questions are
Thoughts on the above?
Are you using something like this?
Do you think its a good pattern (note that I'm only advocating this for web apps that are reliant on their styles).
Your rule may not take due to user stylesheets or other browser settings overriding the rule you're testing on. line-height seems especially vulnerable to this, plus also any rule that takes a length value runs the risk of returning a computedStyle in a different unit to the one you expected, making the string comparison fail. (Not to mention the 1/1px confusion in your example.)
In general I think this needs to fail better. If you think styles haven't loaded, add a warning to the page by all means, but don't replace the whole page with an error, making it completely useless to someone who might have been able to at least try to use it. This fragility is bad for accessibility.
Related
I'm having an issue with updating a web application in Chrome. It’s an ASPX site, but I don’t believe it’s relevant to this conversation. The issue is that our clients don’t get the latest programming in Chrome, because most of the time, it fails to release Javascript and CSS programming from memory, then proceeds to cause all kinds of mayhem while in use.
I tried placing this piece of code in the <head>, like many have suggested, but it doesn’t work all the time.
<script type="text/javascript">
function reload_js(par_src) {
src = $('script[src$="' + par_src + '"]').attr("src");
$('script[src$="' + par_src + '"]').remove();
$('<script/>').attr('src', par_src).appendTo('body');
}
reload_js("../../global/scripts/global_scripts.js");
reload_js("scripts/main.js");
reload_js("scripts/tabs/jquery.ui.core.js");
reload_js("scripts/tabs/jquery.ui.widget.js");
reload_js("scripts/tabs/jquery.ui.mouse.js");
reload_js("scripts/tabs/jquery.ui.sortable.js");
reload_js("scripts/tabs/jquery.ui.tabs.js");
reload_js("scripts/chat_room.js");
</script>
And I use this Javascript file to refresh my css's. One that I found here.
<script src="../../global/scripts/css_refresh.js" type="text/javascript"></script>
I'm scared that these methods cause unnecessary overhead, because they run every time a page is loaded.
Could one of you experts please tell me if this is the most efficient method for updating? Or perhaps recommend a better method to keep these files up to date?
Simplest way to fix this is to add an identifier to the script/style-files. Just add something like ?version=12 (and update the number for each release) then the browser will fetch the newest file. You can also use some sort of server-side date-option after the ?of course, to force a new fetch every day or similar.
I'm doing a couple of things with jQuery in an MTurk HIT, and I'm guessing one of these is the culprit. I have no need to access the surrounding document from the iframe, so if I am, I'd like to know where that's happening and how to stop it!
Otherwise, MTurk may be doing something incorrect (they use the 5-character token & to separate URL arguments in the iframe URL, for example, so they DEFINITELY do incorrect things).
Here are the snippets that might be causing the problem. All of this is from within an iframe that's embedded in the MTurk HIT** (and related) page(s):
I'm embedding my JS in a $(window).load(). As I understand it, I need to use this instead of $(document).ready() because the latter won't wait for my iframe to load. Please correct me if I'm wrong.
I'm also running a RegExp.exec on window.location.href to extract the workerId.
I apologize in advance if this is a duplicate. Indeed - after writing this, SO seems to have a made a good guess at this: Debugging "unsafe javascript attempt to access frame with URL ... ". I'll answer this question if I figure it out before you do.
It'd be great to get a good high-level reference on where to learn about this kind of thing. It doesn't fit naturally into any topic that I know - maybe learn about cross-site scripting so I can avoid it?
** If you don't know, an MTurk HIT is the unit of work for folks doing tasks on MTurk. You can see what they look like pretty quick if you navigate to http://mturk.com and view a HIT.
I've traced the code to the following chunk run within jquery from the inject.js file:
try {
isHiddenIFrame = !isTopWindow && window.frameElement && window.frameElement.style.display === "none";
} catch(e) {}
I had a similar issue running jQuery in MechanicalTurk through Chrome.
The solution for me was to download the jQuery JS files I wanted, then upload them to the secure amazon S3 service.
Then, in my HIT, I called the .js files at their new home at https://s3.amazonaws.com.
Tips on how to make code 'secure' by chrome's standards are here:
http://developer.chrome.com/extensions/contentSecurityPolicy.html
This isn't a direct answer to your question, but our lab has been successful at circumventing (read hack) this problem by asking workers click on a button inside the iframe that opens a separate pop-up window. Within the pop-up window, you're free to use jQuery and any other standard JS resources you want without triggering any of AMT's security alarms. This method has the added benefit of allowing workers to view your task in a full-sized browser window instead of AMT's tiny embedded iframes.
Do browser vendors optimize against jQuery?
I know this sounds absurd anti-standard, but I can imagine browser vendor has optimization against jQuery code built into their JS compiler/interpreter.
For example, lets say the JS compiler/interpreter sees, $('.blah > p'), the browser can say, hmm, I see that user is trying to grab an element, instead of letting jQuery do all the browser detection, it could just take the [actual DOM object], and return $([actual DOM object]) right away.
No guessing what $ does would break any scripts that use $ for different purposes. Consider a page like this (this is actually a pretty weak example relative to what could be found in the wild, but I think it still demonstrates the difficulty well enough):
<div class="bar">
<div class="foo">
<div class="bar">
How will the browser know to select this div with the selector '.bar .foo .bar', without actually running this script the way it is designed?
</div>
</div>
</div>
<script>
window.onload = function(){
var x = $('.foo');
console.log(x);
console.log(x.selector) // '.bar .foo .bar'
};
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var $ = function(){
return arguments[0];
};
$ = (function($){
return function(selector){
return jQuery('.bar ' + selector + ' ' + $('.bar'));
}
})($);
</script>
It would be beyond an optimization for the browser to know which div to select in advance. In fact the browser has to run the scripts the way it is designed to in order to select the correct div.
However many browsers to compile Javascript to a slightly lower level language such as Java or C++ code. Then if the browser downloads and caches jQuery once it will be cached it a compiled form on the users computer. This is not a jQuery specific optimization since it will happen with any cached script, but it is more significant of an optimization for large scripts like jQuery.
No browser vendor announced such a feature at the moment.
It is possible, however. You can easily store for reference parsed Javascript (IL/bytecode, whatever you use in your engine) for most often used versions of jQuery inside JS engine and when incoming function matches that signature, replace it with native version.
I guess the only thing that you have to take in consideration is how much time you'd spend on implementing it vs. speed gains against modern JIT engines. Because some of them already compile code to some native form, at least partially, it is not quite clear if there will be any substantial gains or not.
First of all I am new to javascript so this question might be stupid.
I have a requirement where i would provide a js script to other websites to include in their webpages.
Now my question is should I use jquery or plain javascript.Will/Can jquery effect the rest of the functionality of the site.
Plus what is the benefit I will get using jquery over plain javascript.
My requirement is to get all images of the website and do some processing on the images on these websites.
Thanks in Advance.
I would say, if the processing does not involve jQuery then do not use it.
You need to deal with the following issues if you include it
failure to load (for network reasons)
conflict with other versions locally loaded
conflict with other libraries locally loaded
All issues have workarounds/solutions but you have to implement each an everyone of those.
If you just need to find all images in page, then you can use the .getElementsByTagName() method
var imagelist = document.getElementsByTagName('img');
and just do the processing on that..
You might need of-course to attach your code at the load event to be sure that whatever your code does, the DOM is ready to accept it..
for modern browsers that would be .addEventListener(), while for IE it would be .attchEvent()
your script could be something like this
(function(){ // wrap in a self-invoking function to avoid global name-space pollution
// attach to the load event so out code runs once the page has loaded
if (window.addEventListener) { // modern
window.addEventListener('load', imageProcessor, false);
}
else if (window.attachEvent) { // IE
window.attachEvent('onload', imageProcessor );
}
function imageProcessor(){
// get all images
var imagelist = document.getElementsByTagName('img');
// loop the list of images to do something with each image
for (var img = 0; img < imagelist.length; img++)
{
var currentImage = imagelist[img];
// do processing on the currentImage which hold a reference to the image
}
}
})(); // do the self-invoking
demo: http://jsfiddle.net/gaby/nXPzk/
this would be much more easier to achieve with jQuery, mostly because you want to be able to distribute your script to any browser(and jQuery is a cross-browser library), but it does have it's downsides.
If it's your own project, your own page, you know exactly what and when to load/execute, but if you're giving your script to other folks, you have to think of 3 problems at least:
different libraries conflicts
This can be resolved using jquery's noConflict method, but I've seen it fail in some circumstances
same library conflicts
Say that the user already has loaded version X of jQuery. You oblige him to load version Y too, and besides the fact that this would be very inefficient, it may cause conflicts between different jQuery versions.
There are workarounds for this( to check if jQuery exists and load it asynchroniously if it doesn't) but the code gets a bit more complicated.
code size
When i think of a third party piece of code, I'm thinking...hmm a few kb to load to be able to run a function, but if you want to use jQuery, you may be forcing the one who uses your script to load a whole library just for your one functionality instead of a 1-2 kb (needles to say what the implications are if the user has a slow connection)
Having both the ups and downs in mind, it really depends on what are you doing, so, as Gaby aka G. Petrioli said, " if the processing does not involve jQuery then do not use it".
JQuery is much more convenient than plain javascript. You don't have to worry about cross-browser compatibility (e.g. IE vs. Firefox vs. Chrome). I would recommend this over javascript unless you are want to handle that yourself :)
You can load in the Jquery library, but that might be a little heavy than what you're looking for. Also, you will need to fetch the library from a server, which adds another point of failure (however, if you host this on your own server, then you will have more control).
TLDR: JQuery is convenient. If you have access to it, then you should use it.
I am writing some bookmarklets for a project that I am currently working on and I was wondering what the best practice for writing a bookmarklet was. I did some looking around and this is what I came up with
javascript:void((function()
{
var%20e=document.createElement('script');
e.setAttribute('type','text/javascript');
e.setAttribute('src','http://someserver.com/bookmarkletcode.js');
document.body.appendChild(e)
})())
I felt this is nice because the code can always be changed (since its requested every time) and still it acts like a bookmarklet. Are there are any problems to this approach ? Browser incompatibility etc? What is the best practice for this?
That bookmarklet will append a new copy of the script to the document every time it is run. For long-lived pages (e.g. Gmail), this could add up to a lot of memory usage, and if loading your script has side effects, they’ll occur multiple times. A better strategy would be to give your script an id, and check for existence of that element first, e.g.:
var s = document.getElementById('someUniqueId');
if (s) {
s.parentNode.removeChild(s);
}
s = document.createElement('script');
s.setAttribute('src', 'http://example.com/script.js');
s.setAttribute('type', 'text/javascript');
s.setAttribute('id', 'someUniqueId');
document.body.appendChild(s);
N.B. another alternative is to keep the existing script if it’s already in the document. This might save some server traffic if your bookmarklet is used frequently between page reloads. The worst case is that someone is using an older version of your script for a while; if you don’t expect it to change often, that might be fine.
Looks OK. But if your js file is already cached, it will not be requested every time. So you'd need it to append '?' + new Date() to your src attribute to ensure it is requested every time.