2

I'm creating a plugin where I want to load a few scripts and for each of them run the function plugin.

I created a set of tests/examples (code below).

Questions:

  1. AJAX passes in the usual data, textStatus, jqxhr set of arguments. But apparently also creates a scope where the plugin function is available. Can't find anything about this in the docs. More details/explanation please!

  2. What the heck is the this that seems to be in scope?

  3. The 3rd example where I run get script by mapping off of a list of script names works as expected.

  4. Building a list of deferreds and then running with when acts strangely. I get no indication the functions have run (no output), and when I remove the delays, it always seems to finish first ("done" is printed ahead of everything else). Are the functions running? I tried adding an alert and it does not appear when I use when.

index.js

var script_names = ["one.js", "two.js", "three.js"];

function as_callback(script_name)
{
  console.log("plugin function run as callback");
  console.log(`$.getScript(${script_name}, (data, textStatus, jqxhr) => plugin());`);
  $.getScript(script_name, (data, textStatus, jqxhr) => plugin());
  console.log();
}

function from_this(script_name)
{
  console.log("plugin function referred to from 'this'");
  console.log(`$.getScript(${script_name}, (data, textStatus, jqxhr) => this.plugin());`);
  $.getScript(script_name, (data, textStatus, jqxhr) => this.plugin());
  console.log();
}

function with_map(script_names)
{
  console.log("with map");
  console.log("string_names: " + JSON.stringify(script_names));
  console.log(`
  script_names.map((x) => 
  {
    $.getScript(x, (data, textStatus, jqxhr) => plugin())
  });
  `);
  script_names.map((x) => 
  {
    $.getScript(x, (data, textStatus, jqxhr) => plugin())
  });
  console.log();
}

function with_push_and_when(script_names)
{
  console.log("build array of deferred and run with when");
  console.log(`
  var plugs = [];
  script_names.map(x => $.getScript(x, (data, textStatus, jqxhr) => plugs.push(plugin)));
  $.when(plugs).done(console.log("done"));
  `);
  var plugs = [];
  script_names.map(x => $.getScript(x, (data, textStatus, jqxhr) => plugs.push(plugin)));
  $.when(plugs).done(console.log("done"));
  console.log();
}

as_callback('one.js');

setTimeout("from_this('two.js')", 2000);

setTimeout("with_map(script_names)", 4000);

setTimeout("with_push_and_when(script_names)", 6000);

var plugs = [];
script_names.map(x => $.getScript(x, (data, textStatus, jqxhr) => plugs.push(plugin)));
setTimeout("console.log('run when in global scope');$.when(plugs).done(console.log('done'))", 8000);

one.js

var plugin = function()
{
  console.log("one.js\n\n");
  // alert("one");
  return "one";
}

two.js

var plugin = function()
{
  console.log("two.js\n\n");
  return "two";
}

three.js

var plugin = function()
{
  console.log("three.js\n\n");
  return "three";
}

output

plugin function run as callback
$.getScript(one.js, (data, textStatus, jqxhr) => plugin());

one.js


plugin function referred to from 'this'
$.getScript(two.js, (data, textStatus, jqxhr) => this.plugin());

two.js


with map
string_names: ["one.js","two.js","three.js"]

  script_names.map((x) => 
  {
    $.getScript(x, (data, textStatus, jqxhr) => plugin())
  });


two.js


three.js


one.js


build array of deferred and run with when

  var plugs = [];
  script_names.map(x => $.getScript(x, (data, textStatus, jqxhr) => plugs.push(plugin)));
  $.when(plugs).done(console.log("done"));

done

run when in global scope
done

NOTE: I added the accepted answer to the repl.it.

abalter
  • 9,663
  • 17
  • 90
  • 145
  • Post your code here, not just at a remote site. You can use [Stack Snippets](https://stackoverflow.blog/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/) to make it executable. – Barmar Apr 26 '18 at 18:37
  • 1
    Did you read the docs? – epascarello Apr 26 '18 at 18:37
  • @Barmar -- That only works if you have a single JS file. I don't know how I would demonstrate loading external scripts in that environment. – abalter Apr 26 '18 at 18:42
  • "The script is executed in the global context, so it can refer to other variables and use jQuery functions. Included scripts can have some impact on the current page." – epascarello Apr 26 '18 at 18:43
  • @epascarello Yes. I RTFM. I must be missing the part where it says what environment or scope is available in the callback context. – abalter Apr 26 '18 at 18:43

1 Answers1

2
  1. The callback function runs in the global context, after the script has been loaded. Since the script defines the global variable plugin, it can be accessed from the callback function.

  2. $.getScript doesn't set a specific context, so this will be the global window object. this.plugin is the same as window.plugin, which is the global variable.

  3. That's correct.

  4. $.getScript returns a promise, but you're not pushing them onto plugs, you're just pushing plugin.

Assign the result of .map() to plugs to get the correct array of promises.

var plugs = script_names.map(x => $.getScript(x, (data, textStatus, jqxhr) => plugin()));
$.when(plugs).done(console.log("done"));
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks @Barmar. That makes sense, and answer #4 is so obvious, I should have figured it out myself. – abalter Apr 26 '18 at 19:18