2

How do I modify the below code? I would like to load exactly two scripts before adding next code from function yourCodeToBeCalled. Can someone give a hint for a beginner? I gave my suggestions after comment //.

var loadJS = function(url, implementationCode){//url, url_Next
    //url is URL of external file, implementationCode is the code
    //to be called from the file, location is the location to 
    //insert the <script> element

    var scriptTag = document.createElement('script');//will add scriptTag_Next
    scriptTag.type = 'text/javascript';
    scriptTag.setAttribute('nonce','22os9h3sdfa');
    scriptTag.src = url;

    scriptTag.onload = implementationCode;//Will It be work? -> scriptTag.onload = scriptTag_Next = implementationCode;
    scriptTag.onreadystatechange = implementationCode;//like as above scriptTag_Next.onreadystatechange ??

    document.body.appendChild(scriptTag);
};
var yourCodeToBeCalled = function(){
    console.log('okay'); } loadJS('js/jquery-3_1_1.min.js', yourCodeToBeCalled);//My my suggestion loadJS('js/jquery-3_1_1.min.js', 'js/test.js' yourCodeToBeCalled)

Original code I borrowed from: link

Community
  • 1
  • 1
Zic
  • 83
  • 14
  • "I would like to load exactly two scripts before I add the next code in the same js file" - Can you please re-phrase your statement? – James Poulose Feb 08 '17 at 23:00
  • Why someone lowers rate my topic? I tried a lot of combination to get the correct result.. Is possible load more than one script before next js code? – Zic Feb 08 '17 at 23:03
  • @JamesPoulose In **index.js** I've above code. I want to load (dynamically) two scripts at the end of body markup in index.html but before executing code from "yourCodeToBeCalled" function. Thank you for fast reply :) – Zic Feb 08 '17 at 23:13
  • 1
    Not sure I understand but why not load the scripts twice (by creating 2 script tags and populating) then add your code into another JS file and load that in the same way so you end up loading 3 scripts dynamically. – webnoob Feb 08 '17 at 23:31
  • note: if you need to wait for script loads, don't use `async` on the script element. – Mike 'Pomax' Kamermans Feb 08 '17 at 23:36
  • @webnoob I didn't think that is possible but this can be solution :) – Zic Feb 08 '17 at 23:40
  • @Mike'Pomax'Kamermans Do you mean added dynamically scripts 'scriptTag.async = true;'? btw. main file: **index.js** where I have above code is a 'script async="true" nonce="22os9h3sdfa" type="text/javascript" src="js/index.js">' here I wait for load all dom element – Zic Feb 08 '17 at 23:46
  • Any script with an `async` attribute will cause the browser to immediately move on to the next thing, while loading the script in parallel in the background. If you need to *wait* for scripts, don't use the `async` attribute. So you'd have two script elements, *without* any `async` attribute, followed by a `` element with your "this should load after two scripts" code in it. – Mike 'Pomax' Kamermans Feb 08 '17 at 23:48
  • @Mike'Pomax'Kamermans ok. dynamically scripts haven't `scriptTag.async = true;'` right now. Only 1st script (where I add dynamically scripts) has async. Is this wrong too? and I should change it? – Zic Feb 09 '17 at 00:08
  • 1
    again: if you need to wait for a script, *do not use `async` for that script*. The `async` attribute is for when you explicitly **do not** want to wait for it to finish loading before moving on to the next thing. – Mike 'Pomax' Kamermans Feb 09 '17 at 00:10
  • @Mike'Pomax'Kamermans sure and again sure.. I thought `async` can lighten the landing page (website load faster).. – Zic Feb 09 '17 at 00:19
  • 1
    Nothing is lightened: you *see* the page faster, but the total zero-to-all-data-transfered-parsed-and-active is exactly the same, so the price you pay for your users *only seeing* the page earlier than before is that (a) your users get to interact with with your pages before they are "really done" (there may be some, or even lots of missing functionality) and (b) you are no longer guaranteed any order of events, so if you wanted to "wait for 2 scripts before running script 3", using `async` complete destroys any ability to do that. – Mike 'Pomax' Kamermans Feb 09 '17 at 03:51

3 Answers3

3

OK, I found a way to execute scripts one by one. There are no longer errors due to incorrect order of loading scripts, for example: The lack of jQuery framework when next script uses the command of jQuery.. So I decided to use promises for that case.

var loadJS = function(url) { /*url is URL of external file*/
    return new Promise(function(resolve, reject) {
        var scriptTag = document.createElement('script');
        scriptTag.type = 'text/javascript';
        scriptTag.setAttribute('nonce', '22os9h3sdfa');
        scriptTag.onload = resolve;
        scriptTag.onerror = reject;
        scriptTag.src = url;
        document.body.appendChild(scriptTag);
    });
};

loadJS('js/jquery-3_1_1.min.js').then(() => { return loadJS('js/library.js'); }).then(() => {

    var $ = jQuery.noConflict();//jQuery.noConflict();
});

Now 'jquery-3_1_1.min.js' is executed after 'library.js' etc.

Greetings!

Zic
  • 83
  • 14
  • The nonce attribute seems to be used out of context here. See https://stackoverflow.com/questions/42922784/what-s-the-purpose-of-the-html-nonce-attribute-for-script-and-style-elements – Leo Jan 11 '18 at 23:45
1

I am not sure why you are adding the script element to the location element. Instead of

location.appendChild(scriptTag);

you may want to try

document.body.appendChild(scriptTag);
James Poulose
  • 2,701
  • 1
  • 26
  • 27
  • sure, you right. I've already corrected but still I don't know how join two scripts at once (before yourCodeToBeCalled function) e.g 'first url: js/jquery-3_1_1.min.js & (next script) second url: js/test.js' – Zic Feb 08 '17 at 23:20
1

Assuming I understand your requirements correctly, loadJS is a function, so just call it twice, then call your code:

(function() {
  var head = document.getElementsByTagName('head')
  loadJS('somescript.js', function() { console.log('on load') }, head)
  loadJS('somescript2.js', function() { console.log('on load2') }, head)

  // This is your code to execute once the scripts have loaded.
  console.log('Okay');
})();

Also, you'll want to remove the scriptTag.async = true; line from loadJS so it forces it to wait until it's loaded before continuing execution.

Edit: In line with your most recent change, you can omit the middle param (the callback), it won't be needed.

EDIT: Given your latest changes, this code should work:

(function() {
  loadJS('somescript.js')
  loadJS('somescript2.js')

  // This is your code to execute once the scripts have loaded.
  console.log('Okay');
})();

Now you have document.body.appendChild in loadJS, you don't need the element passed through. Also, you don't need to use a callback, just call your code after the 2 loadJS calls (assuming you've removed the async property).

webnoob
  • 14,765
  • 12
  • 73
  • 149
  • You are so close to solving my problem. I would like to add script in the bottom of body tag, not in head tag like in your case: `getElementsByTagName('head')`. if I add two times `loadJS()` then I would like in first call case without callback. That callback `function() {}` can be optional? – Zic Feb 08 '17 at 23:59
  • Do you even need the callbacks? Can't you just run your code after the `loadJS` calls? – webnoob Feb 09 '17 at 00:17
  • Yes you can but I would like to run code (which is below `loadJS` func) after adding & executing these dynamically scripts. Of course if we can do that :P now I see that you edited your post. So can I remove: `scriptTag.onload = implementationCode;` and `scriptTag.onreadystatechange = implementationCode;` from my func? – Zic Feb 09 '17 at 00:25
  • Here is [my_website](https://horbaczewski.info/) and I use your solution. Current problem is with execution first added script. If you can look at on console/debuger and tell me why jquery not work :( – Zic Feb 09 '17 at 00:46
  • I'm just about to head out so can't look right now but will look when I get a moment. Just out of interest, why are you trying to load these scripts dynamically? Why not load them at the bottom of the body tag manually? – webnoob Feb 09 '17 at 18:59