We have a dynamic adbanner which is loaded onto websites via Google Double Click.
We use some Jquery in the code so as part of the set up we check if a website is running Jquery and if not we use Javascript to add a link to our Jquery file.
This is being done fine however I'm still getting an error "Uncaught ReferenceError: jQuery is not defined" I'd assume this is due to the order things are loading in but I'm not sure how to get around the issue. Everything works fine if you refresh the page the problem only seems to happen on first load.
Also if I open a new browser window and load the page a second time everything works fine.
Here's the code we are using to add the script tags to the head:
if(!window.jQuery)
{
var fm_j = document.createElement('script'); fm_j.type = 'text/javascript';
fm_j.src = 'js/jquery-1.8.3.min.js';
document.getElementsByTagName('head')[0].appendChild(fm_j);
}
This is a timing issue. When you load scripts dynamically like that, they are loaded asynchronously and don't block further execution of javascript on the page. This means that jQuery may not be loaded by the time your jQuery specific code is being run.
When you refresh, js/jquery-1.8.3.min.js has probably been cached and so will load faster, so you don't see errors.
The solution is to wrap your javascript into a function that is called once jQuery has loaded using a load event handler. Here's an example I adapted from this tutorial.
working example.
function getScript(success) {
var fm_j = document.createElement('script');
fm_j.type = 'text/javascript';
fm_j.src = 'js/jquery-1.8.3.min.js',
done = false;
// Attach handlers for all browsers
fm_j.onload = fm_j.onreadystatechange = function () {
if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
done = true;
// callback function provided as param
success();
};
};
document.getElementsByTagName('head')[0].appendChild(fm_j);
};
if(!window.jQuery) {
getScript(doSomething);
} else {
doSomething();
}
Also, as several commentors pointed out, many sites place banner ads inside iframes to keep the ads from "polluting" your page with their libraries.
iFrame could have been a better way to go #flyersun
It's simple and easy and effective, see here
http://support.microsoft.com/kb/272246
Related
I've the following script in my website:
<script type="text/javascript" src="https://code.evidence.io/js/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE2OTh9.2mZpV00Ls3Wgrl7Knm-Bh2z-I7lPaX_5b4d-RbuWl90"></script>
I don't find a way to "delete" it in Google Optimize: is there anyway to see the source code, select this script and "delete" it for the test? (I only see ways to select elements with ID or class, but not scripts).
If not, my best idea is deleting that script from my website and add it to the Google Optimize Global Javascript section.
But I've no idea about how to put that script within that function(){ }
Not sure if that idea has sense actually.
Actually, I see a problem with that idea: I don't find how to add that Javascript code to the whole website as it seems prepared to test single pages.
Note for future people searching for a solution of question: I've also asked the same question here: https://support.google.com/optimize/thread/84843254?hl=en
So a "community specialist" gave me the solution. I hope summarising it here can help somebody else:
If you want to delete a element in the page, that's not
possible. The script has already been executed, removing the
element does not do anything.
The workaround or way to do it is deleting the script in the website.
Then add to Global Javascript (on a Google Optimize variant) the following code to inject the script:
const scriptEl = document.createElement('script');
scriptEl.src = 'https://.....';
document.head.appendChild(scriptEl);
That's working perfectly for me at this time.
Ah, I've not found a way to test the script on the whole website, so I've to create several experiments instead.
--UPDATE--
Script to load the Javascript script everywhere EXCEPT on the Google Optimize pages where we are running the experiment.
In my specific case I've realised the above solution is not enough because I need the script on the whole website to capture the daily number of users on the website.
So have added the following to the head of the website globally:
<!-- Load Javascript script globally except on the page where we are testing it with Google Optimize -->
<script>
if(window.location.href.indexOf("/URL-OR-PART-OF-THE-URL-1/") > -1) {
// (If the URL contains the above, load nothing)
}
else if(window.location.href.indexOf("/URL-OR-PART-OF-THE-URL-/") > -1) {
// (If the URL contains the above, load nothing)
}
else {
// Loads Javascript Evidence pixel
(function () {
var params = {}; // If you want to pass anything, to the called function
var script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
theFunctionInsideExternalScript(params);
}
}
} else {
script.onload = function () {
theFunctionInsideExternalScript(params);
}
}
script.src = "https://SCRIPT-URL-TO-LOAD-GOES-HERE";
document.getElementsByTagName("head")[0].appendChild(script)
})();
}
</script>
The problem:
I execute this script on the My Saves page of Google Images but it selects only one element.
According to the JQuery Documentation:
Note: most jQuery methods that return a jQuery object also loop through the set of elements in the jQuery collection — a process known as implicit iteration. When this occurs, it is often unnecessary to explicitly iterate with the .each() method:
Which means that my code should work on all the elements which have the specified class. But unfortunately, it is carrying out all of the work only on the first element:
$('.col-cv-select').click();
I have also tried using explicit iteration with the .each() method but the browser console throws an error when I use this script:
$('.col-cv-select').each(function (index, element) { element.click(); });
Uncaught TypeError: $(...).each is not a function(…)
I am sure that the page uses JQuery because the first code works quite well, but only selects one element.
Reproducing the problem:
I think you need to be logged in to Google before proceeding.
Go to Google and search for 'unicorns' (or anything you prefer).
Click on the Images tab.
Select any image. Click on Save in the Pop-up.
Repeat the above step with another image.
Next visit the My Saves page.
Fire up your browser console and try the codes above.
Test Environment:
Opera 37.0.2178.43 - Stable (Since it's based on Chromium, hopefully, using Chrome will yield similar behavior)
Windows 8.1 Pro
Hope you can help me out :) Thanks in advance.
Just because the $ variable is defined doesn't mean that jQuery is loaded on the page.
When you run $('.col-cv-select') on that page you're actually running document.querySelector('.col-cv-select') which by design only returns one element.
The reason you're seeing the TypeError about $(...).each not being a function is because the return value of the first function is a DOM node, not a jQuery object.
You can inject the jQuery library into the page by running this code in the developer console: (Taken and adapted from this page)
(function() {
// more or less stolen form jquery core and adapted by paul irish
function getScript(url) {
var script = document.createElement('script');
script.src = url;
var head = document.getElementsByTagName('head')[0],
done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState ||
this.readyState == 'loaded' ||
this.readyState == 'complete')) {
done = true;
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
getScript('https://code.jquery.com/jquery.min.js');
})();
Once you execute that code, the $ variable will be aliased to jQuery and you'll be able to use its .each method and everything else that comes with it.
Just remember that once you reload the page the jQuery library will be unloaded, and to load it again you'll need to re-run the code above.
You need to import jquery into your chrome browser before testing
use the following block of code, before calling your test code
var jq = document.createElement('script');
jq.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
// ... give time for script to load, then type.
jQuery.noConflict();
I provide a JavaScript widget to several web sites, which they load asynchronously. My widget in turn needs to load a script provided by another party, outside my control.
There are several ways to check whether that script has successfully loaded. However, I also need to run different code if that script load has failed.
The obvious tools that don't work include:
I'm not willing to use JavaScript libraries, such as jQuery. I need a very small script to minimize my impact on the sites that use my widget.
I want to detect the failure as soon as possible, so using a timer to poll it is undesirable. I wouldn't mind using a timer as a last resort on old browsers, though.
I've found the <script> tag's onerror event to be unreliable in some major browsers. (It seemed to depend on which add-ons were installed.)
Anything involving document.write is right out. (Besides that method being intrinsically evil, my code is loaded asynchronously so document.write may do bad things to the page.)
I had a previous solution that involved loading the <script> in a new <iframe>. In that iframe, I set a <body onload=...> event handler that checked whether the <script onload=...> event had already fired. Because the <script> was part of the initial document, not injected asynchronously later, onload only fired after the network layer was done with the <script> tag.
However, now I need the script to load in the parent document; it can't be in an iframe any more. So I need a different way to trigger code as soon as the network layer has given up trying to fetch the script.
I read "Deep dive into the murky waters of script loading" in an attempt to work out what ordering guarantees I can count on across browsers.
If I understand the techniques documented there:
I need to place my failure-handling code in a separate .js file.
Then, on certain browsers I can ensure that my code runs only after the third-party script either has run or has failed. This requires browsers that support either:
Setting the <script async> attribute to false via the DOM,
or using <script onreadystatechange=...> on IE 6+.
Despite looking at the async support table, I can't tell whether I can rely on script ordering in enough browsers for this to be feasible.
So how can I reliably handle failure during loading of a script I don't control?
I believe I've solved the question I asked, though it turns out this doesn't solve the problem I actually had. Oh well. Here's my solution:
We want to run some code after the browser finishes attempting to load a third-party script, so we can check whether it loaded successfully. We accomplish that by constraining the load of a fallback script to happen only after the third-party script has either run or failed. The fallback script can then check whether the third-party script created the globals it was supposed to.
Cross-browser in-order script loading inspired by http://www.html5rocks.com/en/tutorials/speed/script-loading/.
var fallbackLoader = doc.createElement(script),
thirdPartyLoader = doc.createElement(script),
thirdPartySrc = '<URL to third party script>',
firstScript = doc.getElementsByTagName(script)[0];
// Doesn't matter when we fetch the fallback script, as long as
// it doesn't run early, so just set src once.
fallbackLoader.src = '<URL to fallback script>';
// IE starts fetching the fallback script here.
if('async' in firstScript) {
// Browser support for script.async:
// http://caniuse.com/#search=async
//
// By declaring both script tags non-async, we assert
// that they need to run in the order that they're added
// to the DOM.
fallbackLoader.async = thirdPartyLoader.async = false;
thirdPartyLoader.src = thirdPartySrc;
doc.head.appendChild(thirdPartyLoader);
doc.head.appendChild(fallbackLoader);
} else if(firstScript.readyState) {
// Use readyState for IE 6-9. (IE 10+ supports async.)
// This lets us fetch both scripts but refrain from
// running them until we know that the fetch attempt has
// finished for the first one.
thirdPartyLoader.onreadystatechange = function() {
if(thirdPartyLoader.readyState == 'loaded') {
thirdPartyLoader.onreadystatechange = null;
// The script-loading tutorial comments:
// "can't just appendChild, old IE bug
// if element isn't closed"
firstScript.parentNode.insertBefore(thirdPartyLoader, firstScript);
firstScript.parentNode.insertBefore(fallbackLoader, firstScript);
}
};
// Don't set src until we've attached the
// readystatechange handler, or we could miss the event.
thirdPartyLoader.src = thirdPartySrc;
} else {
// If the browser doesn't support async or readyState, we
// just won't worry about the case where script loading
// fails. This is <14% of browsers worldwide according to
// caniuse.com, and hopefully script loading will succeed
// often enough for them that this isn't a problem.
//
// If that isn't good enough, you might try setting an
// onerror listener in this case. That still may not work,
// but might get another small percentage of old browsers.
// See
// http://blog.lexspoon.org/2009/12/detecting-download-failures-with-script.html
thirdPartyLoader.src = thirdPartySrc;
firstScript.parentNode.insertBefore(thirdPartyLoader, firstScript);
}
Have you considered using the window's onerror handler? That will let you detect when most errors occur and you can take appropriate action then. As a fallback for any issues not caught this way you can also protect your own code with try/catch.
You should also check that the third-party script actually loaded:
<script type="text/javascript" onload="loaded=1" src="thirdparty.js"></script>
Then check if it loaded:
window.onload = function myLoadHandler() {
if (loaded == null) {
// The script doesn't exist or couldn't be loaded!
}
}
You can check which script caused the error using the url parameter.
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
if (url == third_party_script_url) {
// Do alternate code
} else {
return false; // Do default error handling
}
}
Similar to the way jQuery loads after the document has loaded I need a certain bit of jQuery after a JavaScript script has FINISHED.
I am loading contact data from Google Data API and the div where the data shows up needs to be completely loaded (by the JavaScript) to be accessible by the jQuery if I'm right.
Is there any way to do this?
Let's say you're waiting for Google Analytics to load. Now, you know that when Google Analytics loads, _gaq will be registered on the DOM. So, barring all other (better) asynchronous options, you can create a function that waits for the existence of _gaq:
waitForGaq = function(fn, attemptsLeft) {
var tick = attemptsLeft || 30;
if (typeof(_gaq) != 'object' || !_gaq._getAsyncTracker) {
//_gaq isn't registered yet
if (tick > 1) {
//recurse
setTimeout(function() {
waitForGaq(fn, tick - 1);
}, 100)
}
else {
//no ticks left, log error
log('failed to load window.gaq');
}
}
else {
//gaq is loaded, fire fn
fn();
}
}
So, any code needs to run AFTER _gaq is registered, you can add to the page thusly:
waitForGaq(function() {
//here's all my code...
});
To reiterate: recursing like this is only necessary if the script that you're adding doesn't offer an asynchronous way of interacting with the library. Google Analytics, for one, is kind of a moot example as it offers a cleaner approach:
http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html
Try head.js
It allows to define exactly when (after specific script or after all of them have been loaded) you want to execute particular piece of code.
Not to mention it is by itself very neat.
inject a tag directly after the original with the jQuery code you need to run
<script src="foo" id="bar">
$("#bar").after(
$("<script>").text("some code")
);
if i understand correctly, you want to do something like:
<script>
// your javascript code
</script>
<script>
//your jquery code
</script>
On my web site, I'm trying to accomplishes the fastest page load as possible.
I've noticed that it appears my JavaScript are not loading asynchronously. Picture linked below.
alt text http://img249.imageshack.us/img249/2452/jsasynch2.png
How my web site works is that it needs to load two external JavaScript files:
Google Maps v3 JavaScript, and
JQuery JavaScript
Then, I have inline JavaScript within the HTML that cannot be executed until those two files above are downloaded.
Once it loads these external javascript files, it then, and only then, can dynamically render the page. The reason why my page can't load until both Google Maps and JQuery are loaded is that - my page, based on the geolocation (using Gmaps) of the user will then display the page based on where they are located (e.g. New York, San Francisco, etc). Meaning, two people in different cities viewing my site will see different frontpages.
Question: How can I get my JavaScript files to download asynchronously so that my overall page load time is quickest?
UPDATE:
If I were to download, somehow, Google-maps and JQuery asynchronously, how would I create an event that would be fired once both Google-maps and JQuery have downloaded since my page has a hard dependency on those files to execute.
UPDATE 2
Even though there are 3 answers below, none still actually answer the problem I have. Any help would be greatly appreciated.
HTTP downloads are generally limited by browsers to two simultaneous downloads per domain. This is why some sites have the dynamic content on www.domain.tla and the images and javascript on static.domain.tla.
But browsers act slightly differently with scripts, while a script is downloading, however, the browser won't start any other downloads, even on different hostnames.
The standard solution is to move scripts to the bottom of the page, but there is a workaround that might or might not work for you: Insert the script DOM element using Javascript.
You could use something like this, which works pretty well in most browsers. It has some issues in IE6 at least, but I don't really have the time to investigate them.
var require = function (scripts, loadCallback) {
var length = scripts.length;
var first = document.getElementsByTagName("script")[0];
var parentNode = first.parentNode;
var loadedScripts = 0;
var script;
for (var i=0; i<length; i++) {
script = document.createElement("script");
script.async = true;
script.type = "text/javascript";
script.src = scripts[i];
script.onload = function () {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
};
script.onreadystatechange = function () {
if (script.readyState === "complete") {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
}
};
parentNode.insertBefore(script, first);
}
};
require([
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
"http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
"http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/yuiloader/yuiloader-min.js"
], function () {
console.log(jQuery);
console.log($);
console.log(YAHOO);
});
Someone asked me to comment on this thread, but that was before #lonut posted a response. #lonut's code is a very good solution, but I have some comments (critical and not so critical):
First, #lonut's code assumes that the scripts do NOT have load dependencies on the other scripts. This is a little hard to explain, so let's work with the simple example of jquery.min.js and prototype.js. Suppose we have a simple page that just loads these two scripts like this:
<script src="jquery.min.js"></script>
<script src="prototype.js"></script>
Remember - there's nothing else in the page - no other JavaScript code. If you load that page the two scripts get downloaded and everything's fine. Now, what happens if you remove the jquery.min.js script? If you get errors from prototype.js because it's trying to reference symbols defined in jquery.min.js, then prototype.js has a load dependency on jquery.min.js - you cannot load prototype.js unless jquery.min.js has already been loaded. If, however, you don't get any errors, then the two scripts can be loaded in any order you wish. Assuming you have no load dependencies between your external scripts, #lonut's code is great. If you do have load dependencies - it gets very hard and you should read Chapter 4 in Even Faster Web Sites.
Second, one problem with #lonut's code is some versions of Opera will call loadCallback twice (once from the onload handler and a second time from the onreadystatechange handler). Just add a flag to make sure loadCallback is only called once.
Third, most browsers today open more than 2 connections per hostname. See Roundup on Parallel Connections.
The LABjs dynamic script loader is designed specifically for this type of case. For instance, you might do:
$LAB
.script("googlemaps.js")
.script("jquery.js")
.wait(function(){
// yay, both googlemaps and jquery have been loaded, so do something!
});
If the situation was a little more complex, and you had some scripts that had dependencies on each other, as Steve Souders has mentioned, then you might do:
$LAB
.script("jquery.js")
.wait() // make sure jquery is executed first
.script("plugin.jquery.js")
.script("googlemaps.js")
.wait(function(){
// all scripts are ready to go!
});
In either case, LABjs will download all of the scripts ("jquery.js", "googlemaps.js", and "plugin.jquery.js") in parallel, as least up to the point the browser will allow. But by judicious use of the .wait() in the chain, LABjs will make sure they execute in the proper order. That is, if there's no .wait() in between the two scripts in the chain, they will each execute ASAP (meaning indeterminate order between tehm). If there's a .wait() in between two scripts in the chain, then the first script will execute before the second script, even though they loaded in parallel.
Here is how I've managed to load gmaps asynchronously on a jquery mobile:
First, you can load jquery (i.e. with the require function posted above by Ionuț G. Stan)
Then you can make use of the callback param in gmaps to do the following:
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
var require = function (scripts, loadCallback) {
var length = scripts.length;
var first = document.getElementsByTagName("script")[0];
var parentNode = first.parentNode;
var loadedScripts = 0;
var script;
for (var i=0; i<length; i++) {
script = document.createElement("script");
script.async = true;
script.type = "text/javascript";
script.src = scripts[i];
script.onload = function () {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
};
script.onreadystatechange = function () {
if (script.readyState === "complete") {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
}
};
parentNode.insertBefore(script, first);
}
};
require([
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",], function () {
$.ajax({
type: "GET",
url: 'http://maps.googleapis.com/maps/api/js?v=3&sensor=false&callback=setMyMap',
dataType: "script"
});
});
function setMyMap() {
console.log('your actions here');
var coords = new google.maps.LatLng(40.5439532,-3.6441775);
var mOptions = {
zoom: 8,
center: coords,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("gmap"), mOptions);
}
</script>
<div id="gmap" style="width:299px; height:299px"></div>
</body>
The point is load jquery async (whathever method you choose) and on that callback place a new async call to gmaps with your starting method in the callback param of the gmaps script string.
Hope it helps
Regardless what order they download in, the scripts should be parsed/executed in the order in which they occur on the page (unless you use DEFER).
So, you can put both Google Maps first in the head, THEN JQuery. Then, in the body of your page somewhere:
<script language="Javascript">
function InitPage() {
// Do stuff that relies on JQuery and Google, since this script should
// not execute until both have already loaded.
}
$(InitPage); // this won't execute until JQuery is ready
</script>
But this does have the disadvantage of blocking your other connections while loading the beginning of the page, which isn't so awesome for page performance.
Instead, you can keep JQuery in the HEAD, but load the Google scripts from the InitPage() function, using JQuery's Javascript-loading functionality rather than the Google JSAPI. Then start your rendering when that call-back function executes. Same as the above, but with this InitPage() function instead:
function InitPage() {
$.getScript('Google Maps Javascript URL', function() {
// Safe to start rendering now
});
Move your javascript includes (<script src="...) from the HEAD element to the end of your BODY element. Generally whatever is placed in the HEAD is loaded synchronously, whatever is placed in the BODY is loaded asynchronously. This is more or less true for script includes, however most browsers these days block everything below the script until it is loaded - hence why having scripts included at the bottom of the body is best practice.
Here is the YUI guildline for this which explains it in further detail:
http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html
This is also the reason why stylesheets should be in the head, and javascript should be in the body. As we do not want to see our page turn from spaghetti to niceness while the styles load asynchronously, and we don't want to wait on our javascript while our page loads.
The objective you have in mind would be served by using requireJS. RequireJS downloads the js resources asynchronously. Its a very simple and useful library to implement. Please read more here. http://requirejs.org/