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 всегда иметь приоритет перед обработчиком загрузки?

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

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!
  1. Ваш OnLoad будет вызван, когда JS в другом месте завершит анализ (асинхронные функции сделают свое дело). Например, otherScriptFunc(); позвоню раньше onload но setTimeout(otherScriptFunc, 0); будет вызван после onload

  2. Ваш OnError будет вызываться только в случае ошибки запроса GET. То есть, файл не может быть найден, или URL не может быть разрешен - ничего о том, что находится в файле. (Я проверял это отдельно, просто возиться с именем файла)

  3. Ваш обратный вызов, переданный другому скрипту, может быть вызван всякий раз, когда другой скрипт захочет. У него есть ссылка на него, и он мог бы немного подождать и позвонить позже, после того, как он поигрался. Это означает, что это может быть в асинхронном вызове, ожидающем данные в другом месте. Это означает, что теоретически ваша нагрузка на самом деле может быть вызвана до обратного вызова, но это зависит от другого сценария, и вы ничего не можете с этим поделать.

Будет ли эта функция json_callback всегда иметь приоритет перед обработчиком загрузки?

Речь идет не о приоритете, а о том, когда другой скрипт решит его вызвать.

Другие вопросы по тегам