1

I develop a library that needs to load async in pages. My script load:

<script type="text/javascript">
  (function(w,d) {
    var po = d.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'my_function-sdk.js';
    var s = d.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })(window, document);
</script>

I want to use the function immediately below:

<script>
      my_function("test");
</script>

Or in a click:

<a href="#" onclick="my_function('other test');">test click</a>

The function definition in file my_function-sdk.js:

function my_function(param) {
  console.log("in correct function");
  console.log(param);
}

I want that console.log print "in correct function" how was defined in my function on file my_function-sdk.js.

JSFiddle: https://jsfiddle.net/adrianogodoy/n7ahygoj/8/

EDIT: I want to do like Google Analytics, using ga function immediately bellow the load script or any other place without receive a not defined error:

  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
     m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXXXX-1', 'auto');
    ga('send', 'pageview');
</script>
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Adriano Godoy
  • 1,488
  • 1
  • 11
  • 21
  • Maybe a dummy question, but, why you cant use the traditional include line HTML? – Marcel Kohls Apr 25 '16 at 14:39
  • It's a good question. The library actually has more functions. It estimates that its size will be about 100kb, so I can not impact the load time of the sites where it will be used. – Adriano Godoy Apr 25 '16 at 14:45

7 Answers7

1

You are executing my_function independently of whether the script has loaded or not. You can create an onload / onreadystatechange event handler that will execute a callback function after the script has loaded:

po.onload = po.onreadystatechange = function() { my_function("text") };
Ozrix
  • 3,489
  • 2
  • 17
  • 27
  • Thanks for the answer. I think that this is the right way, but I want to execute the function outside the (function(w,d) { ... }); , like Google Analytics does. Furthermore, I want to execute the function from external loaded script. – Adriano Godoy Apr 25 '16 at 13:32
1

Solved!

Before load script, the temporary function needs to queue the calls until the true function load.

<script type="text/javascript">
  (function(w,d) {
    w['my_function'] = w['my_function'] || function() {
      (w['my_function'].q = w['my_function'].q || []).push(arguments)
    }
    var po = d.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://rawgit.com/Godoy/830e372b7aa73158d68633bd15acb781/raw/7aaf95e41b30ee72fc7504bdac3475bc66fbec31/my_function-sdk.js';
    var s = d.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })(window, document);
</script>

Queue with .push(arguments) in a array attribute q.

So, in external script (my_function-sdk.js file), pop the queue and call the real function for each element in the queue:

(function () {
  // Pop the call queue...
  q = window['my_function'].q;
  while(a = q.pop()){
    my_real_function(a);
  }

  //copy the complete function under old that was stacking queue
  my_function = my_real_function;
})();

// real function that will execute things
function my_real_function(params) {
  console.log("execute real function on remote file");
  console.log(params);
}

https://jsfiddle.net/adrianogodoy/na67hqj0/

Adriano Godoy
  • 1,488
  • 1
  • 11
  • 21
0

Adriano, I believe that this kind of code will not work because you are trying to add a JS file after the page was already loaded, so the browser will not load the content of your js script. Try to research about this topic.

Marcel Kohls
  • 1,650
  • 16
  • 24
  • I've edited my question to simplify. I want to execute the function defined in the included file, like Google Analytics does. – Adriano Godoy Apr 25 '16 at 13:20
  • So, that´s what I said. The included file will not load the functions on it this way. Take a look on this topic, with the same problem. It have some alternatives of how to do it: http://stackoverflow.com/questions/950087/include-a-javascript-file-in-another-javascript-file – Marcel Kohls Apr 25 '16 at 13:25
0

Adriano, I made an example of how you can do it in a simple way using the eval resourse and the functions as an object. Take a look https://jsfiddle.net/MarcelKohls/ghzuszzf/.

var externalString = "funcs={myFunction:function(param){console.log(param);} , otherFunction:function(){x=10+10; return x;}};"

var functions=eval(externalString);

functions.myFunction('test'); // this writes to console
alert(functions.otherFunction());

I do not recommend to use the eval, but it can be a step closer to you.

Also, as I said before, just including the js file on the document it will not be available to use the functions on it. Google analytics make a lot of work on the lib to turn the content on to working functions.

Anyway, the sample above can show you something. Good luck there.

Marcel Kohls
  • 1,650
  • 16
  • 24
0

Here a sample way of how to load the JS after the content of page is loaded: https://jsfiddle.net/MarcelKohls/g9hssz9t/

<script type="text/javascript">
   function downloadJSAtOnload() {
   var element = document.createElement("script");
   element.src = "https://rawgit.com/Godoy/c8cba89030c44e163997ed675c7fc0cd/raw/d67b5788c35a039e554d58e4dd24e57b9e5d519c/my_function-sdk.js";
   document.body.appendChild(element);
 }
  if (window.addEventListener)
  window.addEventListener("load", downloadJSAtOnload, false);
  else if (window.attachEvent)
      window.attachEvent("onload", downloadJSAtOnload);
  else window.onload = downloadJSAtOnload;
</script>

// here the JS call for the function
setTimeout(function(){ my_function('text here'); }, 3000); 

I put the setTimeout to simulate the delay of the page but is better to put this call on the end of the file that you include, than you will make sure that the call will be done when the included file is loaded 100%.

Marcel Kohls
  • 1,650
  • 16
  • 24
  • Thanks @Marcel, but the problem is just that I need to make function calls spread in the code, not sure if the asynchronous file already loaded. – Adriano Godoy Apr 25 '16 at 16:06
0

And here a more simple way using jquery .getScript()

https://jsfiddle.net/MarcelKohls/oom4w4j5/

$( document ).ready(function() {
  $.getScript( "external-lib.js", function( data, textStatus, jqxhr ) {
    my_function('test content after page loaded');
  });
});
Marcel Kohls
  • 1,650
  • 16
  • 24
-1

You function declaration is not getting a parameter, try this:

(function(w,d) {
  w.my_function=function(value) { console.log(value); };
  var po = d.createElement('script'); po.type = 'text/javascript'; po.async = true;
  po.src = 'https://rawgit.com/Godoy/c8cba89030c44e163997ed675c7fc0cd/raw/d67b5788c35a039e554d58e4dd24e57b9e5d519c/my_function-sdk.js';
  var s = d.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})(window, document);


my_function("test");
Danilo Silva
  • 612
  • 2
  • 7
  • 16