А? Угловой $ инжектор: ошибка Nomod... теги сценария async / defer забавные, $.readyWait/$. HoldReady кажется сломанным

=== TL;DR ===

Короткая версия (поверь мне, я весь день обдумывал это):

У меня есть большой список сценариев, включая угловые и не угловые (1.2.x). Когда я пытаюсь использовать LAB.js для загрузки всего этого, включая флаг AlwaysPreserveOrder, Angular запускается слишком рано. Похоже, Angular использует $(document).ready(/* start angular */). Понятно, что загрузчики скриптов подрывают обычное событие document.ready.

Итак, я пытаюсь использовать $.holdReady(true) и $.holdReady(false), но я получаю действительно странное поведение: хотя $.holdReady(true) действительно увеличивает $.readyWait, как и ожидалось, это просто не предотвратит угловое от инициализации... и, кроме того, если я попытаюсь установить свой собственный слушатель для $(document).ready(), он никогда не сработает, даже если angular, по-видимому, использует это же событие для запуска...

... Чтобы добавить к тайне, каждый раз в голубой луне, если я настрою ее продолжать выполнять window.location.reload() при сбое до тех пор, пока все не заработает, на самом деле это будет просто работать - очень редко. Это делает его похожим на состояние гонки, но, учитывая, что я передаю флаг заказа, я не могу представить, что будет гонкой, и эта подсказка, насколько я могу судить, кажется, не вписывается во все остальное.,

Обратите внимание, что если я переключусь на версию файла, отличную от lab.js, все будет работать нормально, включая подсчет $.readyWait, все (включая угловое), ожидающее вызова $.holdReady(false), $ (документ).ready () флаг моей собственной стрельбы и т. д.

====== ДЛИННАЯ ВЕРСИЯ ======

Я пытаюсь привести как минимум жизнеспособный пример, но здесь доступен более сложный реальный рабочий код, а здесь- неработающая версия - они все еще очищены, чтобы попытаться сделать проблему как можно более очевидной, без устранения каких-либо потенциально мешающих факторов.

Это работает:

<body ng-app="mapmycustomersApp" ng-strict-di>
      <script src="build/libraries/LAB.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js"></script>
      <script src="https://code.angularjs.org/1.2.32/angular-resource.min.js"></script>
      <script src="https://code.angularjs.org/1.2.32/angular-route.min.js"></script>

      <script>
         document.write('<script src="build/app.js"></script>')
         document.write('<script src="build/controllers/main.js"></script>')
      </script>
</body>

Это не:

<body ng-app="mapmycustomersApp" ng-strict-di>
      <script src="build/libraries/LAB.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js"></script>
      <script src="https://code.angularjs.org/1.2.32/angular-resource.min.js"></script>
      <script src="https://code.angularjs.org/1.2.32/angular-route.min.js"></script>

      <script>
         $LAB.setGlobalDefaults({ AlwaysPreserveOrder: true });
         $LAB
         .script("build/app.js")
         .script("build/controllers/main.js")
      </script>
</body>

И не делает этого:

<body ng-app="mapmycustomersApp" ng-strict-di>
      <script src="build/libraries/LAB.min.js"></script>

      <script>
         $LAB.setGlobalDefaults({ AlwaysPreserveOrder: true });
         $LAB
         .script("https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.min.js")
         .script("https://code.angularjs.org/1.2.32/angular-resource.min.js")
         .script("https://code.angularjs.org/1.2.32/angular-route.min.js")
         .script("build/app.js")
         .script("build/controllers/main.js")
      </script>
</body>

Третий (последний чуть выше) - это то, что я действительно хочу.

Они выдают эту ошибку:

Модуль 'mapmycustomersApp' не доступен! Вы либо неправильно написали имя модуля, либо забыли загрузить его. При регистрации модуля убедитесь, что вы указали зависимости в качестве второго аргумента.

При написании этого ответа я добился некоторого прогресса, но столкнулся с новым тупиком, который, клянусь, ощущается как ошибка в jquery или angular.

Зачем? Самая дальняя спина, которую я могу проследить, говорит мне, что angularInit() вызывается слишком рано, задолго до того, как приложение зарегистрируется... Это вызывается внизу углового файла, в строке 2232:

  jqLite(document).ready(function() {
    angularInit(document, bootstrap);
  });

Для jqLite установлено значение jQuery (я подтвердил это, проверив, что angular.element === $, что верно, что подтверждается в другом месте углового кода). Так что это должно быть только стрельба по $(document).ready(). У которого были известные проблемы с загрузчиками. Именно поэтому они создали $.holdReady().

Но по какой-то причине это не работает для меня.И я получаю очень странный вывод.

Вот что я имею в виду: если переместить тег сценария jquery (2.2.4) в верхнюю часть головы, а затем вызвать $.holdReady(true) прямо под ним я вижу $.readyWait увеличивается (Я даже могу назвать это несколько раз для хорошей меры, и смотреть, как это идет до четырех.)

Затем я вставляю .wait(() => $.readyWait(false)) в конце моего .script() звонки... но если я консоль.log прямо перед этим, я вижу, что он упал с, скажем, 4 в 0 уже означает готовность уже уволен. $.readyWait() Ничего не сделал.

Ценная подсказка:

Очень редко нерабочий код работает... и затем снова завершается неудачей при обновлении без изменений. Казалось бы, это указывает на состояние гонки, но я не могу понять, где это будет, и это не совпадет с тем, что я видел... пока что это происходит. В те времена $.readyWait возвращает 1 вместо 0.

Я знаю, что это много, но я чувствую себя совершенно сбитым с толку. Что происходит в мире?

О, еще одна очень важная подсказка, которая сбила меня с толку: $(document).ready(_ => console.log("I loaded")) никогда не бежит. $(window).load, в остальном идентичный, работает нормально. Неважно, где я объявляю этого слушателя, он просто никогда не срабатывает для меня, даже если я устанавливаю слушателя в верхней части страницы... и все же он явно срабатывает как-то, потому что это то, что срабатывает angularInit! Насколько я понимаю, он должен выстрелить, если я призову его, даже если он уже выстрелил!

... просто чтобы показать, что я не делаю невероятно очевидную ошибку, все тот же код срабатывает, как и ожидалось (document ready событие, а holdReady() оба делают именно то, что вы ожидаете) всякий раз, когда я переключаюсь на все теги сценария.

В коде:

<!doctype html>
<html>
  <head>
    <script src="https://code.jquery.com/jquery-2.2.4.js"></script>
    <script>
      $(window).load(function() {
         console.log("this fires");
      });
      $(document).ready(function() {
        console.log("this doesn't");
        debugger;
      });
      console.log("holding ready", $.readyWait);
      $.holdReady(true);$.holdReady(true);$.holdReady(true); // needed because we use LAB.js, which messes with Document.ready, which Angular depends on
      console.log('rw, ', $.readyWait)
    </script>

(подробности:app.js включает в себя

var app = angular.module('mapmycustomersApp' ['ngRoute','ui.bootstrap','ngStorage','ngFileUpload'])
.config(['$routeProvider', '$locationProvider', '$compileProvider', function($routeProvider, $locationProvider, $compileProvider) { // ...

а также main.js включает в себя

app.controller('MainCtrl', ['$scope', '$http', // ...

Весь код функционален, я просто пытаюсь перенести все в LAB.js и не могу. Другие комментарии: переход на angular 1.6.4 просто для удовольствия не имеет никакого эффекта (за исключением полной неудачной загрузки при тех редких успехах, потому что $http(). Success не является функцией, поэтому они должны были изменить этот API в более поздней версии) и мы находимся на последней версии jquery в версии 2, и переключение на 3+ приводит к другим ошибкам несовместимости.

1 ответ

Я был прав в определении проблемы. В длительной дискуссии с Кайлом Симпсоном он отметил, что использование $.ready в угловой версии 1.2x исходный код является распространенной ошибкой, основанной на неверных предположениях, которая делает загрузку источников javascript асинхронно нежизнеспособной.

С помощью $.holdReady() в конце концов, по какой-то причине сработало Я не уверен, почему это не так, но я подозреваю, что я случайно включил зависимость jquery дважды, перезаписывая предыдущий readyCount.

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