Paste the script tag with remote src and wait for it to execute
How can I insert the <script src="https://remote.com/"></script> element into my page, wait for it to execute, and then use the functions that it defines?
FYI: In my case, the script will process some credit cards in rare cases, so I do not want to include it always. I want to enable it quickly when the user opens the change-credit-card-options dialog, and then send him new credit card parameters.
Edit for more info: I do not have access to the remote script.
You can use the Google Analytics or Facebook method:
(function(d, script) { script = d.createElement('script'); script.type = 'text/javascript'; script.async = true; script.onload = function(){ // remote script has loaded }; script.src = 'http://www.google-analytics.com/ga.js'; d.getElementsByTagName('head')[0].appendChild(script); }(document)); UPDATE:
Below is the new Facebook method; it relies on an existing script tag instead of <head> :
(function(d, s, id){ var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)){ return; } js = d.createElement(s); js.id = id; js.onload = function(){ // remote script has loaded }; js.src = "//connect.facebook.net/en_US/sdk.js"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); - Replace
facebook-jssdkwith your unique script identifier to avoid adding it more than once. - Replace the script url with yours.
The same method using event listeners and ES2015 constructs:
function injectScript(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.async = true; script.src = src; script.addEventListener('load', resolve); script.addEventListener('error', () => reject('Error loading script.')); script.addEventListener('abort', () => reject('Script loading aborted.')); document.head.appendChild(script); }); } injectScript('http://example.com/script.js') .then(() => { console.log('Script loaded!'); }).catch(error => { console.log(error); }); This is one way to dynamically load and execute a list of scripts synchronously. You need to insert each script tag in the DOM, explicitly setting its async attribute to false:
script.async = false; Scripts that were implemented in the DOM are executed asynchronously by default, so to bypass this async attribute, you must manually set the value to false.
Example
<script> (function() { var scriptNames = [ "https://code.jquery.com/jquery.min.js", "example.js" ]; for (var i = 0; i < scriptNames.length; i++) { var script = document.createElement('script'); script.src = scriptNames[i]; script.async = false; // This is required for synchronous execution document.head.appendChild(script); } // jquery.min.js and example.js will be run in order and synchronously })(); </script> <!-- Gotcha: these two script tags may still be run before 'jquery.min.js' and 'example.js' --> <script src="example2.js"></script> <script>/* ... */<script> References
- There is an excellent article by Jake Archibald from Google called Deep Immersion in the Troubled Waters of Downloading Scripts .
- The WHATWG specification for a tag is a good and detailed description of how tags are loaded.
something like this should do the trick:
(function() { // Create a new script node var script = document.createElement("script"); script.type = "text/javascript"; script.onload = function() { // Cleanup onload handler script.onload = null; // do stuff with the loaded script! } // Add the script to the DOM (document.getElementsByTagName( "head" )[ 0 ]).appendChild( script ); // Set the `src` to begin transport script.src = "https://remote.com/"; })(); hope this helps! amuses.
Dynamic import()
Using dynamic imports, you can now load modules and wait for them to execute, just like that:
import("http://example.com/module.js").then(function(module) { alert("module ready"); }); If the module has already been loaded and executed, it will not be loaded and executed again, but the promise returned by import will still be fulfilled.
Please note that the file is loaded as a module, not as a script. Modules are executed in strict mode and loaded in the scope of the module, which means that the variables do not automatically become global, as in normally loaded scripts. Use the export keyword in a module to share the variable with other modules or scripts.
References:
Create bootloader
You can embed the script in an ordered manner in the bootloader.
Remember that execution of dynamically loaded scripts usually occurs after statically loaded scripts (i.e. <script src="My_script.js"></script> ) (the implementation order in the DOM does not guarantee the opposite):
e.g. loader.js:
function appendScript(url){ let script = document.createElement("script"); script.src = url; script.async = false //IMPORTANT /*Node Insertion Point*/.appendChild(script); } appendScript("my_script1.js"); appendScript("my_script2.js"); my_script1.js will execute efficiently before my_script2.js , (useful if my_script2.js dependencies are in my_script1.js )
Please note that it is important to have script.async = false , because dynamically loaded scripts have async = true by default, async does not guarantee you the load order.