注入了innerHTML的脚本不会触发onload和onerror

Script injected with innerHTML doesn't trigger onload and onerror

本文关键字:onload onerror innerHTML 脚本 注入      更新时间:2023-09-26

我正在尝试绑定script标签的onloadonerror事件。当从src加载时,这工作得很好。给定以下函数:

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);
}

我可以很容易地知道脚本是否已加载:

> injectJS("https://code.jquery.com/jquery-3.1.1.min.js");
Success!
> injectJS("https://raw.githubusercontent.com/eligrey/FileSaver.js/master/FileSaver.js");
Error!

但是当使用innerHTML注入内联JS时,脚本不会触发事件:

> injectJS("console.log('"Yes!'");", true);
Yes!
> injectJS("console.log('"Loaded but error...'"); error;", true);
Loaded but error...

Success!在这些情况下没有被记录。但是,我可以在前面加上一些可以调用函数的代码,例如,一旦脚本加载。

当出现错误导致脚本无法加载时,问题就出现了,例如语法错误:

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

不记录任何内容(当然,错误除外)。如何在加载之前检测注入脚本是否已加载或错误?

编辑:

Oriol的回答为我指明了正确的方向。作为参考,下面是最终的函数,它完全按照我想要的方式工作,并且通过了5个测试用例:
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();
        }
    }
}

内联脚本同步加载。所以你根本不需要事件。

只使用

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);

您将无法检测语法错误,但就像使用外部脚本一样。error事件仅表示脚本无法下载,而不是语法错误。