Javascript onload и функции обратного вызова скрипта, который имеет приоритет?
Я загружаю внешний скрипт, который использует функцию обратного вызова, которая возвращает определенные данные. Если эти данные не получены, должна отображаться ошибка.
Вот код, который я сделал:
<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 и устанавливает переменную members_loaded так, чтобы функция обработчика вызывалась только один раз.
Пока что он отлично работает в JS fiddle и на моем офлайновом сайте, но мне интересно, это ожидаемое поведение? Будет ли эта функция json_callback всегда иметь приоритет перед обработчиком загрузки?
3 ответа
Будет ли эта функция json_callback всегда иметь приоритет перед обработчиком загрузки?
Если внешний скрипт вызывает my_callback
синхронно тогда да.
scripting
В разделе официальной спецификации html5 описывается, как эти вещи должны работать. Спецификация является довольно общей и имеет дело со многими деталями, касающимися кодирования, CORS, ignore-destructive-writes counter
и так далее. Но по этому вопросу нас не волнует эта специфика.
На шаге 4 есть примечание:
Примечание. Здесь сценарий компилируется и фактически выполняется.
И на шаге 7 load
событие происходит:
запустить простое событие с именем load в элементе script.
Таким образом, спецификация определяет, что load
Событие всегда вызывается после выполнения скрипта.
Как вы видите, спецификация также говорит нам, почему onerror
событие не запускается, если вы измените URL. error
событие создается только в случае сбоя загрузки скрипта. Но все просьбы https://api.clicky.com/api/stats/
вернуть статус HTTP 200. Недопустимые URL-адреса возвращают XML, и, таким образом, выдается SyntaxError. Но это не вызывает onerror
обработчик для запуска.
Как уже упоминали другие, если обратный вызов вызывается асинхронно, они могут вызвать обратный вызов после onload
событие. Но я не вижу причины, почему они сделали бы эту асинхронность в вашем внешнем сценарии.
onload в более старом IE может не работать с обработчиком "onload" для тега "script" в 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));
};
Теперь проблема в том, что, если все загружено нормально и данные возвращены, будет запущена функция обратного вызова и onload. Я заметил, что функция обратного вызова запускается перед onload и устанавливает переменную members_loaded так, чтобы функция обработчика вызывалась только один раз.
Это связано с тем, что обратный вызов запускается из вызываемого скрипта с сайта api.clicky.com.
Пока что он отлично работает в JS fiddle и на моем офлайновом сайте, но мне интересно, это ожидаемое поведение?
Я вижу, к чему вы клоните, здесь есть связанный вопрос о том, что происходит в случае сбоя скрипта, но я сделал несколько тестов для вас, и вот результаты.
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!
Ваш
OnLoad
будет вызван, когда JS в другом месте завершит анализ (асинхронные функции сделают свое дело). Например,otherScriptFunc();
позвоню раньшеonload
ноsetTimeout(otherScriptFunc, 0);
будет вызван послеonload
Ваш
OnError
будет вызываться только в случае ошибки запроса GET. То есть, файл не может быть найден, или URL не может быть разрешен - ничего о том, что находится в файле. (Я проверял это отдельно, просто возиться с именем файла)Ваш обратный вызов, переданный другому скрипту, может быть вызван всякий раз, когда другой скрипт захочет. У него есть ссылка на него, и он мог бы немного подождать и позвонить позже, после того, как он поигрался. Это означает, что это может быть в асинхронном вызове, ожидающем данные в другом месте. Это означает, что теоретически ваша нагрузка на самом деле может быть вызвана до обратного вызова, но это зависит от другого сценария, и вы ничего не можете с этим поделать.
Будет ли эта функция json_callback всегда иметь приоритет перед обработчиком загрузки?
Речь идет не о приоритете, а о том, когда другой скрипт решит его вызвать.