【问题标题】:Script injected with innerHTML doesn't trigger onload and onerror注入 innerHTML 的脚本不会触发 onload 和 onerror
【发布时间】:2016-11-17 19:11:58
【问题描述】:

我正在尝试绑定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 的answer 为我指明了正确的方向。作为参考,这里是完全按照我的意愿工作并通过 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();
        }
    }
}

【问题讨论】:

  • 忽略?它们对我来说运行良好。问题是检测它们何时加载。
  • 如何检测注入的脚本在加载前是否已加载或出错? 你不能。
  • @ScottMarcus Oh..
  • 要检测错误,您可以尝试window.onerror,或者将脚本内容包装在一个大的try 块中。
  • 我不是想检测脚本中的错误,我只是想看看它是否加载。无论如何谢谢:)

标签: javascript


【解决方案1】:

Inline scripts are loaded synchronously。所以你根本不需要这些事件。

随便用

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 事件仅意味着无法下载脚本,而不是语法错误。

【讨论】:

  • 哦,我不知道。我很愚蠢,因为我还没有弄清楚这一点。谢谢!
  • 然后我会做一些事情,比如在每个脚本的开头添加window.script_loaded = true; 并检查它。如果为 true,则将其设置为 false 并调用 success 回调。否则调用error 回调。
  • @Slayther 让我坚持认为这是不一致的。 injectJS("parse error", true, _=>console.log("Success!"), _=>console.log("Error!")); 将记录错误,但 injectJS("data:text/javascript,parse error", false, _=>console.log("Success!"), _=>console.log("Error!")); 将记录成功。 loaderror 事件不应该验证脚本,只通知它是否可以获取。
  • 我实际上认为第二种情况是成功的,因为知道脚本是否加载对我来说很重要。如果它是外部脚本,则错误不会起作用,而只有 HTTP 或其他(例如特定于浏览器)脚本本身之外的错误。
  • 您可以在我的问题中看到这一点。第二种情况是完美运行的 JS 的 URL。由于 Chrome 出现错误:Refused to execute script from 'https://raw.githubusercontent.com/eligrey/FileSaver.js/master/FileSaver.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.,脚本未加载,它必须调用 error 回调。
猜你喜欢
  • 2015-04-18
  • 2020-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多