Почему мой обратный вызов API Карт Google выполняется перед предыдущим встроенным скриптом? - PullRequest
0 голосов
/ 28 февраля 2020
<script src="/js/site.js?v=EtZhOXlkRte5HDRXpfS7rDy3ua0sbCvtNJUaIlNsSXw"></script>
<script>
    var init;
    $(function () {
        var adpSummaryListenerId;
        init = _initializeDirections;
        initializeAdpSummaryListener();

        function _initializeDirections() {
            console.log("test"); //we don't get here, sometimes
            var origin = {
                isGoogle: $("#origin-isgoogle").val(),
                coordinate: new google.maps.LatLng(@origin.Latitude, @origin.Longitude),
                address: "@origin.StreetAddress",
                marker: "@origin.MarkerName"
            }, destination = {
                isGoogle: $("#destination-isgoogle").val(),
                coordinate: new google.maps.LatLng(@destination.Latitude, @destination.Longitude),
                address: "@destination.StreetAddress",
                marker: "@destination.MarkerName"
            }, start = {
                value: origin.isGoogle ? origin.address : origin.coordinate,
                pos: origin.coordinate,
                marker: origin.marker
            }, end = {
                value: destination.isGoogle ? destination.address : destination.coordinate,
                pos: destination.coordinate,
                marker: destination.marker
            };

            console.log("Initializing directions");
            initializeDirections(start, end); //in site.js
        }

        function initializeAdpSummaryListener() {
            adpSummaryListenerId = window.setInterval(addNavigateButton, 500);
        }

        function addNavigateButton() {
            console.log("checking for .adp-summary");
            if ($(".adp-summary").length) {
                $(".adp-summary").append($("#start-navigation").html());
                clearInterval(adpSummaryListenerId);
            }
        }
    });
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=@(Model.GoogleMapsApiKey)&callback=init"></script>

Я не могу понять, почему, несмотря на ссылку на скрипт карт после встроенного скрипта, обратный вызов API Карт Google init иногда не создается до того, как Google попытается вызвать его.

Это ошибка, которую я получаю:

Uncaught (in promise)
ld {message: "init is not a function", name: "InvalidValueError", stack: "Error at new ld (https://maps.googleapis.com/.......&callback=init:141:124"}

Ранее у меня было имя обратного вызова как initializeMap как ссылка, объявленная на сайте. js (но все еще инициализированная здесь в встроенный сценарий), но перенес его сюда для краткости и изоляции, надеясь, что смогу разобраться в проблеме. Но та же проблема сохраняется.

Я понимаю , что async направляет API-интерфейс для извлечения параллельно с синтаксическим анализом и оценкой, как только он становится доступным, но он не должен быть доступен до встроенного сценария, верно?

Я также понимаю, что defer означает, что API не будет выполняться до тех пор, пока документ не будет проанализирован, поэтому он еще не должен быть доступен.

Я видел это о defer:

Этот атрибут позволяет исключить блокировку синтаксического анализатора JavaScript, когда браузер должен будет загружать и оценивать скрипты, прежде чем продолжить анализ. asyn c имеет аналогичный эффект в этом случае.

Но defer по-прежнему не должен препятствовать выполнению встроенного скрипта первым, потому что он только позволяет JavaScript , чтобы не иметь необходимости быть блокирующим парсер , если атрибут используется для встроенного тега <script>.

Так что я в растерянности.

1 Ответ

2 голосов
/ 28 февраля 2020

Вышеупомянутый встроенный скрипт действительно выполняется первым, но $(function () { - это конструкция jQuery, которая запускает обратный вызов внутри, как только документ готов. Похоже, что сначала запускается скрипт Google.

Если вы дадите скрипту Google атрибут defer, он запустится только после завершения построения DOM, и $(function () { не понадобится. Итак, просто переместите все из $(function () {, чтобы init был на верхнем уровне, и вызывалось Google при загрузке скрипта Google:

<script>
function init() {
            var origin = {
                isGoogle: $("#origin-isgoogle").val(),
                coordinate: new google.maps.LatLng(@origin.Latitude, @origin.Longitude),
                address: "@origin.StreetAddress",
                marker: "@origin.MarkerName"
            }, destination = 
            // etc

Обратите внимание, что пока вы можете использовать async или defer, вы не должны использовать оба. Чтобы дождаться загрузки DOM, используйте defer, а не async.

. Есть одна вещь, которую ваш выше встроенный скрипт делает, кроме как присваивать переменным, то есть call initializeAdpSummaryListener. Вы можете поместить это в $(function () {, если вам нужно убедиться, что DOM загружен перед запуском:

$(initializeAdpSummaryListener);

Еще одна опция, поток управления которой может быть легче понять, это поставить все в именованной функции, которую Google вызывает при загрузке (что, учитывая атрибут defer, произойдет только после загрузки страницы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...