Loading javascript asynchronously - How to do callbacks?
I am building a javascript widget that should load asynchronously.
Problem is that there can be more than 1 of these widgets on the page and that the widget should be initialized by sending it an option array via {}.
What is the best way to accomplish this? I heard that simply setting onload or onreadystatechange does not work in all browsers.
I've checked out the digg widget, but I can't really comprehend what they're doing, c开发者_JS百科ould anyone take a look at that?
Here's some of their code:
(function () {
var s, s1, diggWidget = {
id: "digg-widget-1282651415272",
width: 300,
display: "tabbed"
};
if (window.DiggWidget) {
if (typeof DiggWidget == 'function') {
new DiggWidget(diggWidget);
} else {
DiggWidget.push(diggWidget);
}
} else {
DiggWidget = [diggWidget];
s = document.createElement('SCRIPT');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://widgets.digg.com/widgets.js';
s1 = document.getElementsByTagName('SCRIPT')[0];
s1.parentNode.insertBefore(s, s1);
}
})();
So, if the DiggWidget is already available (loaded earlier due to multiple instances), it makes a new widget if DiggWidget is a function, otherwise DiggWidget is used as an array and the current settings are pushed to it.
First, why would DiggWidget ever be a function?
If the widget is the only one (or first), the script tag is added asynchronously, no callbacks are defined.
Then, looking at widgets.js they do this:
At the top:
(function () {
var A;
if (window.DiggWidget) {
if (typeof DiggWidget != "function") {
A = DiggWidget
} else {
return
}
}
At the bottom:
if (A) {
while (A.length) {
new DiggWidget(A.shift())
}
}
Now I don't quite understand this. Is DiggWidget (the array) available to that .js ? It's in a anonymous function. So if I include such a script twice, wouldn't DiggWidget be a new instance every time?
Or am I completely in the wrong on this? Sorry if so. If there's any better methods to have a callback with multiple instances of the script, please do tell.
First, why would DiggWidget ever be a function?
It will become a function when the asynchronous script loads and executes
Is DiggWidget (the array) available to that .js
Yes, window.DiggWidget
is global so it's available to that script.
The way the widget works is rather simple.
If the DiggWidget
script has not been loaded yet, then window.DiggWidget
will not be a function. Initially it will be an undefined variable so the else block
} else {
DiggWidget = [diggWidget];
executes and defines it as an array. From now onwards and until the widget script loads, it will be defined as an array.
Now until the DiggWidget
script loads asynchronously, keep pushing all initialization objects {..}
to an array of the same name - window.DiggWidget
.
When the script is loaded, before it overtakes the global DiggWidget
variable it sees the objects in that array, and safely records it somewhere else. Then takes over the DiggWidget name, loops through each object, and initializes the widget for each.
Here's the full embed code annotated with comments.
User code
(function () {
var s, s1, diggWidget = {
id: "digg-widget-1282651415272",
width: 300,
display: "tabbed"
};
// either the external widget script has already loaded, or there is more than
// one widget to be embedded on the page, and the previous widget's embed code
// defined this variable
if (window.DiggWidget) {
// the external widget script has been loaded asynchronously
// because DiggWidget is a function. Can directly create a new object.
if (typeof DiggWidget == 'function') {
new DiggWidget(diggWidget);
}
// a previous widget's embed code defined this global array. Remember the
// widgets initialization settings for when the external script loads.
else {
DiggWidget.push(diggWidget);
}
}
// the external widget script has not loaded yet and
// this is the first widget ever to be embedded on the page
else {
// DiggWidget does not exist at this point. So make it an array
// and store the first widget's config object in it
DiggWidget = [diggWidget];
s = document.createElement('SCRIPT');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://widgets.digg.com/widgets.js';
s1 = document.getElementsByTagName('SCRIPT')[0];
s1.parentNode.insertBefore(s, s1);
}
})();
Widget code (at the top)
(function () {
var A;
// global DiggWiget is defined. it will either be an array if
// the widget code hasn't loaded yet, or a function if it has
if (window.DiggWidget) {
// it's an array, so keep that array somewhere safe
// because we are gonna take over the DiggWidget variable purdy soon
if (typeof DiggWidget != "function") {
A = DiggWidget
}
// window.DiggWidget must be a function
// there is no widget to initialize, just return
else {
return
}
}
(at the bottom)
// A is the array of widget settings we backed up a little earlier
if (A) {
// loop through each config object and create the actual
// widget object
while (A.length) {
new DiggWidget(A.shift())
}
}
精彩评论