Javascript onload和script回调函数,哪个优先?

Javascript onload and script callback functions, which takes the precedence?

我正在加载一个使用回调函数的外部脚本,其中 returns 一些特定数据。如果未收到此数据,则应显示错误。

这是我编写的代码:

<script>
//setting initial state so that function will only work once
var visitors_loaded=false;  
var my_callback = function( data ) {
    if (visitors_loaded) return 0;
    if (data) { 
        //success: callback function is called and it has a proper data
    visitors_loaded=true;
    alert(JSON.stringify(data));
    }
    else alert ('error'); //something went wrong
};
</script>
<script onload="my_callback(null)" onerror="my_callback(null)"
src="https://api.clicky.com/api/stats/4?site_id=32020&sitekey=9a19b1a4d1171193&type=visitors&date=this-month&output=json&json_callback=my_callback"></script>

如您所见...脚本可能会出现很多问题,因此我很自然地添加了一个 onerror 事件。如果您将脚本的主机名或域更改为不存在的内容,则此错误事件实际上会触发。

但是,如果您只对脚本的 url 进行更改,它仍然可以连接到服务器并触发 onload 事件代替。那些无效请求不会调用我的回调函数,所以我也添加了一个 onload 处理程序。

现在的问题是,如果所有加载正常并返回数据,它将同时触发回调函数onload。我注意到回调函数在 onload 之前触发并设置了 visitors_loaded 变量,这样处理函数只被调用一次。

到目前为止,它在 JS fiddle 和我的离线站点中运行良好,但我想知道这是否是预期的行为? json_callback 函数是否总是优先于 onload 处理程序?

https://jsfiddle.net/5sfk9ht5/4/

Now the problem is, if all loaded normally and data was returned, it will fire both, callback function and onload. I have noticed that callback function is triggered before the onload and set the visitors_loaded variable so that the handler function is only called once.

这是因为回调是从 api.clicky.com

的调用脚本中启动的

So far it works perfectly in JS fiddle and my offline site but I wonder if this is an expected behavior?

我明白你的意思了,一个关于脚本失败时会发生什么的相关问题是 here,但我为你做了一些测试,结果如下。

tester.html:

<script>

var onLoadTest = function() {
    console.log("Onload Called!");
};


var callbacktest = function() {
    console.log("Called from other script!");
};

var errortest = function() {
    console.log("Callback OnError!");
};

</script>

 <script onload="onLoadTest()" onerror="errortest()"
 src="script.js"></script>

script.js:

function otherScriptFunc()
{    
    //call the function in the original script
    callbacktest()
}

otherScriptFunc(); // first call to other script
setTimeout(otherScriptFunc, 0); // final call to other script

来自控制台日志的结果

Called from other script!
Onload Called!
Called from other script!
  1. 你的OnLoad会在其他地方的JS解析完成后被调用(异步函数会做自己的事情)。例如,otherScriptFunc(); 将在 onload 之前调用,但 setTimeout(otherScriptFunc, 0); 将在 onload

  2. 之后调用
  3. 你的OnError只有在GET请求错误时才会被调用。 IE,找不到文件,或无法解析 URL - 与文件中的内容无关。 (我单独测试了一下,就是把文件名弄乱了)

  4. 您传递给其他脚本的回调可以在其他脚本需要时调用。它有一个对它的引用,可以决定保留它一段时间,然后在它玩完之后再调用它。这意味着它可能在异步调用中等待其他地方的数据。这意味着,理论上,您的 onload 实际上可以在回调之前调用,但这取决于其他脚本,您对此无能为力。

Will that json_callback function always have precedence before the onload handler?

这与优先级无关,仅取决于其他脚本何时决定调用它。

onload 在旧版 IE 中可能不适合你'onload' handler for 'script' tag in internet explorer, if you want to run all browsers you might need something like this https://jsfiddle.net/e287523t/2/但应该适合所有人

      function addScript(fileSrc, callback) {
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.onreadystatechange = function() {
          if (this.readyState == 'complete') {
            callback();
          }
        } 
        script.onload = callback;
        script.src = fileSrc;
        head.appendChild(script);
     }

然后剩下的就是定义my_callback和调用addScript

        my_callback = function(someData) {
          alert(JSON.stringify(someData));
        };

Will that json_callback function always have precedence before the onload handler?

如果外部脚本同步调用 my_callback 那么是。

官方 html5 specification 中的 scripting 部分描述了这些东西应该如何工作。该规范非常笼统,必须处理许多有关编码、CORS、ignore-destructive-writes counter 等的细节。但是对于这个问题我们不关心这些细节。

在第 4 步中有一个注释:

Note: This is where the script is compiled and actually executed.

并且在第 7 步中触发了 load 事件:

fire a simple event named load at the script element.

因此规范定义 load 事件总是在脚本执行后触发。


如您所见,规范还告诉我们为什么在更改 URL 时不会触发 onerror 事件。 error 事件仅在加载脚本失败时创建。但是所有对 https://api.clicky.com/api/stats/ return 的请求都是 HTTP 200 状态。无效的 URLs return XML 并因此抛出 SyntaxError。但这不会导致 onerror 处理程序被触发。


正如其他人提到的,如果异步调用回调,他们可以在 onload 事件之后调用您的回调。但我看不出他们会在您的外部脚本中执行此异步操作的原因。