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

时间:2016-06-11 09:21:09

标签: javascript callback onload onerror external-script

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

以下是我制作的代码:

<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 事件。如果您将脚本的主机名或域更改为不存在的内容,则会发生此错误事件。

但是,如果您只更改了脚本的网址,它仍然可以连接到服务器并激活 onload 事件。我的回调函数不会被调用那些无效的请求,所以我也添加了 onload 处理程序。

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

到目前为止它在JS小提琴和我的离线网站上运行得很好,但我想知道这是否是预期的行为?在 onload 处理程序之前, json_callback 函数是否总是优先?

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

3 个答案:

答案 0 :(得分:3)

  

json_callback函数在onload处理程序之前是否总是优先?

如果外部脚本同步调用my_callback,则为是。

官方html5 specification中的scripting部分描述了这些事情应该如何运作。该规范非常通用,必须处理许多详细信息,包括编码,CORS,ignore-destructive-writes counter等。但对于这个问题,我们并不关心这些细节。

在第4步中有一个注释:

  

注意:这是脚本编译和实际执行的地方。

在第7步中,load事件被触发:

  

在脚本元素上触发一个名为load的简单事件。

因此规范定义了在执行脚本后始终触发load事件。

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

正如其他人提到的,如果异步调用回调,他们可以在onload事件后调用你的回调。但我没有看到他们为什么会在你的外部脚本中执行此异步的原因。

答案 1 :(得分:2)

  

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

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

的被调用脚本中启动的
  

到目前为止它在JS小提琴和我的离线网站上运行得很好,但我想知道这是否是预期的行为?

我看到你得到了什么,关于脚本失败时会发生什么的相关问题是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. 当其他地方的JS完成解析时,将调用OnLoad(异步函数会自行执行)。例如,otherScriptFunc();将在onload之前调用,但setTimeout(otherScriptFunc, 0);将在onload之后调用

  2. 只有在发出GET请求错误时才会调用OnError。 IE,无法找到文件,或无法解析URL - 无论文件中有什么内容。 (我单独测试过,只是弄乱了文件名)

  3. 只要其他脚本感觉到,就可以调用传递给其他脚本的回调。它有一个参考,并可能决定保持一段时间,并在它播放后调用它。这意味着它可能在异步调用中等待其他地方的数据。从理论上讲,这意味着你的onload实际上可以在回调之前被调用,但它取决于其他脚本,并且你可以做很多事情。

  4.   

    在onload处理程序之前,json_callback函数是否总是优先?

    这不是关于优先权,它只取决于其他脚本何时决定调用它。

答案 2 :(得分:1)

旧版IE中的

onload可能对您不起作用'onload' handler for 'script' tag in internet explorer,如果您想运行所有可能需要此类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));
        };