Using getScript synchronously
Solution 1
As I said, it's relatively easy to chain Ajax calls with promise objects. Now, it don't see why the scripts have to be loaded one after the other, but you will have a reason for it.
First though I would get rid of the switch
statement if you are only calling the same function with different arguments. E.g. you can put all the script URLs in a map:
var scripts = {
'#FFF': '...',
'#000': '...'
// etc.
};
You can chain promises by simply returning another promise from a callback passed to .then
[docs]. All you need to do is start with a promise or deferred object:
var deferred = new $.Deferred();
var promise = deferred.promise();
for (var i in divlist) {
// we need an immediately invoked function expression to capture
// the current value of the iteration
(function($element) {
// chaining the promises,
// by assigning the new promise to the variable
// and returning a promise from the callback
promise = promise.then(function() {
return loadScript(
scripts[$element.css("background-color")],
$element
);
});
}($('#' + divlist[i])));
}
promise.done(function() {
// optional: Do something after all scripts have been loaded
});
// Resolve the deferred object and trigger the callbacks
deferred.resolve();
In loadScript
, you simply return the promise returned from $.getScript
or the one returned by .done
:
function loadScript(script_url, $element){
// Unrelated stuff here!!!
return $.getScript(script_url).done(function(){
// Unrelated stuff here
// do something with $element after the script loaded.
});
}
The scripts will all be called in the order the are access in the loop. Note that if divlist
is an array, you really should use normal for
loop instead of a for...in
loop.
Solution 2
This worked for me, and may help you.
$.ajax({
async: false,
url: "jui/js/jquery-ui-1.8.20.min.js",
dataType: "script"
});
Basically, I just bypassed the shorthand notation and added in the async: false
Solution 3
Do you know that $.getScript
accepts a callback function that is called synchronously after the script is loaded?
Example:
$.getScript(url,function(){
//do after loading script
});
I have 2 more solutions: a pure js one and one for multiple js load.
Solution 4
Try this way, create array with deferred objects and used $.when with "apply"
var scripts = [
'src/script1.js',
'src/script2.js'
];
var queue = scripts.map(function(script) {
return $.getScript(script);
});
$.when.apply(null, queue).done(function() {
// Wait until done, then finish function
});
Related videos on Youtube
VashGH
Updated on July 25, 2022Comments
-
VashGH almost 2 years
I'm writing an engine that requires the use of getScript quite extensively. I've pushed it into its own function, for ease of use, but now I need to make sure that the function itself is synchronous. Unfortunately, I can't seem to make getScript wait until the script it loads is actually finished loading before proceeding. I've even tried setting jQuery's ajax asynch property to false before making the call. I'm thinking of using jQuery's when/done protocol, but I can't seem to wrap my head around the logic of placing it inside a function and making the function itself synchronous. Any help would be very much appreciated!
function loadScript(script){ //Unrelated stuff here!!! $.when( $.getScript(script,function(){ //Unrelated stuff here!!! })).done(function(){ //Wait until done, then finish function }); }
Loop code (by request):
for (var i in divlist){ switch($("#"+divlist[i]).css({"background-color"})){ case #FFF: loadScript(scriptlist[0],divlist[i]); break; case #000: loadScript(scriptlist[2],divlist[i]); break; case #333: loadScript(scriptlist[3],divlist[i]); break; case #777: loadScript(scriptlist[4],divlist[i]); break; } }
-
Felix Kling about 11 yearsThere is no need to make
loadScript
synchronous. Just return the promise object form$.getScript
and let the calling code bind a callback. Or why exactly do you think it has to be synchronous? -
VashGH about 11 yearsI'm looping through a variable length array (varies by the page it's on) of divs using a for-in loop and performing a series of instructions with them, including loading scripts. The problem is, the scripts have to be loaded after the previous has finished loading and executing. Unfortunately, I've not been able to find a suitable way of "waiting" for an object to exist in javascript, yet. Intervals work well, except for the fact that it is all inside of that for-in loop for the div's.
-
Felix Kling about 11 yearsAre you applying the same commands on each
div
(I assume so since it's a loop) but load a different script for each div? Could you post some code? It's easy to chain Ajax calls using deferred objects. -
VashGH about 11 yearsUpdated with the basic idea. Perhaps you can think of up a better way of doing it.
-
Felix Kling about 11 yearsI provided a suggestion.
-
-
VashGH about 11 yearsThat runs synchronously and makes sure the script is finished loading prior to executing any other code?
-
Roger C about 11 yearsRight, scripts are loaded synchronously unless you add the async attribute
-
Roger C about 11 yearsI could have sworn they were loaded synchronously but it seems it's not the case, I'm sorry for misleading you.
-
VashGH about 11 yearsMy main problem is that I need it within a function (because I use the same 20 lines or so of code all over the place), and I need the function itself to be synchronous. That code just gives me a callback for when the scripts finish loading. getScript already has that feature.
-
kupriyanenko about 11 yearsMaybe then you should look at AMD architecture and use requirejs with modules dependencies? requirejs.org/docs/api.html#modulename
-
VashGH about 11 yearsdeferred.resolve() throws an error (function doesn't exist) and the code doesn't execute as expected.
-
Felix Kling about 11 yearsMmmh. The deferred / promise objects changed a bit in the recent jQuery versions. I updated the example and hope it works now.
-
VashGH about 11 yearsThat did the trick. Thanks for not only solving my problem, but exposing me to a new method of performing chained tasks. This deferred/promise logic is very intriguing!
-
Felix Kling about 11 yearsYeah, it's great way to decouple code, abstract from synchronous/asynchronous code, etc. I love it :) You can read more about the original proposal for JavaScript (which was more basic) here: wiki.commonjs.org/wiki/Promises/A and of course on Wikipedia: en.wikipedia.org/wiki/Futures_and_promises.
-
foxontherock almost 5 yearsThat's the only method I found to do a sync "fallback" of some js files, without using "document.write". All others methods using DOM manipulation were always async even when setting async=false. The dom "appendBefore" occurs too late. The "xhr" method is really sync and on the next line, my variables are available to use. I know it's deprecated, but in how many years... document.write is also deprecated, and still works. And I think there's no other "sync" solution of scripts loading fallback directly in "html source".
-
kmuenkel about 3 yearsMuch appreciated for answering the question directly. I'm swimming in some legacy code at the moment, where handling things 'properly' isn't an option without massive refactors, so this is a good stop-gap for me.