我正在加载一个使用回调函数的外部脚本,该函数返回一些特定数据。如果未收到此数据,则应显示错误。
以下是我制作的代码:
<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 函数是否总是优先?
答案 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!
当其他地方的JS完成解析时,将调用OnLoad
(异步函数会自行执行)。例如,otherScriptFunc();
将在onload
之前调用,但setTimeout(otherScriptFunc, 0);
将在onload
之后调用
只有在发出GET请求错误时才会调用OnError
。 IE,无法找到文件,或无法解析URL - 无论文件中有什么内容。 (我单独测试过,只是弄乱了文件名)
只要其他脚本感觉到,就可以调用传递给其他脚本的回调。它有一个参考,并可能决定保持一段时间,并在它播放后调用它。这意味着它可能在异步调用中等待其他地方的数据。从理论上讲,这意味着你的onload实际上可以在回调之前被调用,但它取决于其他脚本,并且你可以做很多事情。
在onload处理程序之前,json_callback函数是否总是优先?
这不是关于优先权,它只取决于其他脚本何时决定调用它。
答案 2 :(得分:1)
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));
};