Slayther Slayther - 1 year ago 103
Javascript Question

Script injected with innerHTML doesn't trigger onload and onerror

I am trying to bind

onload
and
onerror
events of
script
tag. This works fine when loading from src. Given the following function:

function injectJS(src, inline) {
var script = document.createElement("script");

if (inline) {
script.innerHTML = src;
} else {
script.src = src;
}

script.onload = function() {console.log("Success!");};
script.onerror = function() {console.log("Error!");};

document.body.appendChild(script);
}


I can easily know whether script has loaded:

> injectJS("https://code.jquery.com/jquery-3.1.1.min.js");
Success!

> injectJS("https://raw.githubusercontent.com/eligrey/FileSaver.js/master/FileSaver.js");
Error!


But when injecting inline JS, with innerHTML, the script doesn't fire the events:

> injectJS("console.log(\"Yes!\");", true);
Yes!

> injectJS("console.log(\"Loaded but error...\"); error;", true);
Loaded but error...


Success!
hasn't been logged in these cases. However, I could just prepend some code that can call a function, for example, once the script is loaded.

The problem comes when there is an error that prevents script from loading in the first place, for example a syntax error:

> injectJS("console.log(\"Success! Or not..\"); syntax error;", true);


Nothing is logged (except the error, of course). How can I detect whether an injected script has loaded or errored out before loading?

Edit:

Oriol's answer has pointed me in the right direction. For reference, here is the final function that works exactly as I wanted and passes all 5 test cases:

function injectJS(src, inline, on_success, on_error) {
var script = document.createElement("script");

script.onload = on_success;
script.onerror = on_error;

if (inline) {
script.innerHTML = "window.script_loaded = true; " + src;
} else {
script.src = src;
}

document.body.appendChild(script);

if (inline) {
var loaded = window["script_loaded"];
window.script_loaded = false;

if (loaded) {
on_success();
} else {
on_error();
}
}
}

Answer Source

Inline scripts are loaded synchronously. So you don't need the events at all.

Just use

function injectJS(src, inline) {
  var script = document.createElement("script");
  script.onload = function() {console.log("Success!");};
  script.onerror = function() {console.log("Error!");};
  if (inline) {
    script.innerHTML = src;
    script.onload();
  } else {
    script.src = src;
  }
  document.body.appendChild(script);
}
injectJS("console.log(\"Yes!\");", true);

You won't be able to detect syntax errors, but it's just like with external scripts. The error event only implies the script couldn't be downloaded, not syntax errors.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download