0

The first time pica() is used, it will load the external library. However, if pica() is used a second time before it finishes loading the external JS, it should not load the library a second time so alert() will run.

let picaStatus = 0;

function pica(...args) {
  if (picaStatus == 1) { // library previously loaded
    pica.resizeCanvas(...args);
  } else if (picaStatus == 0) { // library hasn't been loaded
    picaStatus = -1;
    $.getScript("//cdnjs.cloudflare.com/ajax/libs/pica/2.0.4/pica.min.js", () => {
      picaStatus = 1;
      pica.resizeCanvas(...args);
    });
  } else if (picaStatus == -1) { // library is currently being loaded by another call
    alert('loading collision');
  }
}

Instead of throwing an alert() and dropping the function call, how can I make the second function call wait until the library is loaded?

davidtgq
  • 3,780
  • 10
  • 43
  • 80

2 Answers2

1

Make the status a promise for the loaded script:

let picaStatus = null;

function pica(...args) {
  if (!picaStatus) { // library hasn't been loaded
    picaStatus = $.getScript("//cdnjs.cloudflare.com/ajax/libs/pica/2.0.4/pica.min.js");
  }
  picaStatus.then(() => {
    pica.resizeCanvas(...args);
  });
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • When the second call to `pica()` arrives and `picaStatus` is still falsey, wouldn't the `picaStatus = $.getScript()` still run a second time? – davidtgq Jan 31 '17 at 01:13
  • 1
    No, because when it runs the first time the variable is set to a non-falsey value - the promise. – Bergi Jan 31 '17 at 01:17
1

It's generally discouraged to use blocking function calls in order to load resources. Instead, you should utilize the asynchronous nature of JavaScript by using callbacks or promises. You probably also don't want to store the state of the function in some kind of global variable, so you should use an IIFE to wrap up that state.

const pica = (function() {
    let picaScript;
    return function(...args) {
        picaScript = picaScript || 
            $.getScript("//cdnjs.cloudflare.com/ajax/libs/pica/2.0.4/pica.min.js");
        picaScript.then(() => pica.resizeCanvas(...args));
    };
})();
4castle
  • 32,613
  • 11
  • 69
  • 106
  • I'm not sure I understand the flow of this code... using `const pica` makes the value of `let picaScript` persist? – davidtgq Jan 31 '17 at 01:09
  • @DavidTan When you return a function from inside a function, all of the local variables referred to by the returned function are persisted. This creates what is called a [closure](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work). – 4castle Jan 31 '17 at 01:16
  • Hm this seems clever but too advanced for me as a hobbyist... :) Is this functionally different from the code in Bergi's answer? – davidtgq Jan 31 '17 at 01:18
  • @DavidTan Other than the closure, we presented two ways of writing the same code. – 4castle Jan 31 '17 at 01:18