Slayther Slayther - 17 days ago 7
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

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.

Comments