Skrypty ładowane asynchronicznie z domcontentloaded lub load event handlers nie są wywoływane?

Mam skrypt z DOMContentLoaded event handler-

document.addEventListener('DOMContentLoaded', function() {
    console.log('Hi');
});

Które Ładuję asynchronicznie -

<script async src=script.js></script>

Jednak Obsługa zdarzenia nigdy nie jest wywoływana. If I load it synchronously -

<script src=script.js></script>
Działa dobrze.

(nawet jeśli zmienię Zdarzenie DOMContentLoaded na load, nigdy nie zostanie wywołane.)

Co się dzieje? Obsługa zdarzeń powinna być zarejestrowana niezależnie od tego, jak skrypt jest ładowany przez przeglądarkę, nie?

Edit : nie działa na Chrome 18.0.1025.11 beta, ale z DOMContentLoaded, to robi na Firefoksie 11 beta (ale z load nie). Pomyśl.

[[8]] O WIELCY WŁADCY JAVASCRIPT I DOM, MÓDLCIE SIĘ POKAZAĆ BŁĄD MOICH SPOSOBÓW!
Author: user1203233, 2012-02-11

4 answers

Ładując skrypt asynchronicznie, mówisz przeglądarce, że może załadować ten skrypt niezależnie od innych części strony. Oznacza to, że strona może zakończyć ładowanie i może odpalić DOMContentLoaded przed załadowaniem skryptu i przed zarejestrowaniem zdarzenia. Jeśli tak się stanie, przegapisz wydarzenie (stało się to już po zarejestrowaniu się na nie).

W niektórych przeglądarkach można przetestować dokument, aby sprawdzić, czy jest już załadowany. Nie sprawdziłem wszystkich przeglądarek kompatybilność, ale w Firefoksie 3.6+ ( MDN doc) można sprawdzić:

if (document.readyState !== "loading")

Aby sprawdzić, czy dokument jest już załadowany. Jeśli tak, to rób swoje. Jeśli tak nie jest, zainstaluj detektor zdarzeń.

W rzeczywistości, jako źródło odniesienia i pomysł implementacji, jQuery robi to samo ze swoją metodą .ready() i wygląda na szeroko wspierane. jQuery ma ten kod po wywołaniu .ready(), który najpierw sprawdza, czy dokument jest już załadowany. Jeśli tak, to nazywa gotowy funkcja natychmiast zamiast wiązania detektora zdarzeń:

// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
    // Handle it asynchronously to allow scripts the opportunity to delay ready
    return setTimeout( jQuery.ready, 1 );
}
 52
Author: jfriend00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-08 01:30:14

To nie jest ostateczna odpowiedź, ale pozwoliło mi zrozumieć, dlaczego nie jest poprawne użycie async ze skryptem, który musi zmodyfikować DOM, więc musi czekać na Zdarzenie DOMContentLoaded. Nadzieja może być korzystna.

Tutaj wpisz opis obrazka

(Źródło: uruchamianie kodu we właściwym czasie z kirupa.com )

 20
Author: Manuel Solorzano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-29 20:06:11

Jednym z sposobów obejścia tego problemu jest użycie zdarzenia load na obiekcie window.

Stanie się to później niż DOMContentLoaded, ale przynajmniej nie musisz się martwić o pominięcie zdarzenia.

window.addEventListener("load", function () {
   console.log('window loaded');
});

Jeśli naprawdę chcesz złapać Zdarzenie DOMContentLoaded, możesz użyć obiektu Promise. Obietnica zostanie rozwiązana, nawet jeśli stało się to wcześniej:

HTMLDocument.prototype.ready = new Promise(function (resolve) {
if (document.readyState != "loading")
    return resolve();
else
    document.addEventListener("DOMContentLoaded", function () {
        return resolve();
    });
});

document.ready.then(function () {
    console.log("document ready");
});
 3
Author: user4617883,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 19:11:07

Symulowanie powolnego połączenia 3G przy użyciu Chrome devtools miałem problemy z manipulacją DOM z zewnętrznego skryptu async, jednak ten fragment, który znalazłem gdzieś na Githubie rozwiązał mi to:

var DOMReady = function(callback) {document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback);};
DOMReady(function() {
  //DOM is ready!
});
Czy ktoś może za to poręczyć?
Jak to wygląda w porównaniu z już zaproponowanymi rozwiązaniami?
Znalazłem też podobne rozwiązanie tutaj:
https://javascript.info/onload-ondomcontentloaded#readystate
 1
Author: Malvoz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-06 22:00:16