Проблемы с порядком загрузки модулей JavaScript

Репозиторий Github: https://github.com/leighhobson89/ChipshopChopper

Мне трудно заставить один файл .js запустить свой код до того, как это попытается сделать другой. Суть проблемы в том, что я вызываю функцию через событие отправки в одном файле (давайте вызовем ее 1.js), а вызываемая ею функция находится во втором файле (давайте вызовем ее 2.js). Однако, несмотря на то, что функция вызывается при срабатывании диспетчеризации событий, переменная, в которую она должна записываться в этой функции, возвращается неопределённой (она объявлена ​​над функцией в 2.js).

Я попытался объявить эту переменную в 1.js перед отправкой события и его экспортом, но затем получил сообщение об ошибке, сообщающее, что вы не можете назначить константную переменную. Весь смысл этого упражнения в том, чтобы иметь эту константу в отдельном файле, потому что это большой длинный список элементов DOM, и я не хочу продолжать вызывать document.getElementById() каждый раз, когда хочу повлиять на innerHTML элемента, поэтому я создал событие для запуска вызова этой функции в том месте кода, где я хочу, чтобы она загрузила ее, т. е. после создания элементов, но до того, как их запросят на изменение.

Мне нужен способ, кроме defer или сортировки порядка в HTML или помещения скрипта в тег <head> (все это я пробовал безуспешно), заставить его инициализировать переменную в 2.js, прежде чем что-либо делать в 1.js .

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

Из онлайн-исследований я попробовал:

  • defer чтобы попробовать сделать 1.jsзагрузку перед 2.js
  • поставив 1.js в тег <head>
  • создание Promise в функции, которая устанавливает переменную elements, чтобы разрешить, когда элементы имеют значение, отличное от нуля или неопределенного (но у меня нет хороших навыков асинхронного программирования, так что, возможно, это было правильно или нет)
  • изменение порядка тегов <script> в HTML-файле.

1.js:

let elements;

export function setElements() {
      elements = {
        option1: document.getElementById('option1'),
        option2: document.getElementById('option2'),
        //etc
      }

2.js

import {getElements, setElements} from './1.js'

document.addEventListener('titleScreenCreated', setElements);
const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
//code that creates various elements
document.dispatchEvent(titleScreenCreatedEvent);
console.info(getElements());
//code that changes elements
// getElements().option1.innerHTML = "hello world";

index.html

<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <link rel = "stylesheet" href = "styles.css">
    <title>Your Game</title>
</head>
<body>
<div class = "clock">00:00:00</div>
<script type = "module" src = "actions.js"></script>
<script defer type = "module" src = "1.js"></script>
<script type = "module" src = "ui.js"></script>
<script type = "module" src = "2.js"></script>
</body>
</html>

Трудно понять вашу проблему, не видя упрощенного примера кода.

Yousaf 08.05.2024 14:55

@Yousaf Я добавил несколько упрощенных примеров и весь файл index.html.

Leigh Hobson 08.05.2024 15:35

При нынешней настройке он никогда не будет заполнен правильно, поскольку все ваши модули совместно используются только в том случае, если они происходят из одного корня модуля. Поэтому, если вы импортируете оба файла в единый файл импорта, он может начать работать. Прямо сейчас импорт 1.js с использованием тега script, который загружается в 2.js, будет отдельным экземпляром из 2.js, загруженного с помощью тега script.

somethinghere 08.05.2024 15:52

Привет, Ли, добро пожаловать в StackOverflow! Я не думаю, что проблема в том, где вы предполагаете. Я запустил ваш код (после нескольких исправлений синтаксиса), и он печатает элементы getElements так, как и ожидалось. К сожалению, вам придется глубоко погрузиться в эти «огромные участки кода» с помощью отладчика, чтобы выяснить, что происходит не так. Я предлагаю вам поместить точки останова в установщик и геттер в качестве первого шага, чтобы проверить порядок выполнения.

Tamas Hegedus 08.05.2024 15:58

@somethinghere Он загрузился только один раз, когда я тестировал в Chrome

Tamas Hegedus 08.05.2024 16:02

@somethinghere спасибо за ответ. К сожалению, я не смог в полной мере понять то, на что вы намекали. Не могли бы вы написать пару строк псевдокода, которые дали бы мне представление о том, как мне следует изменить структуру импорта и в каких файлах это сделать?

Leigh Hobson 08.05.2024 16:22

@TamasHegedus спасибо за ответ. Возможно, вы правы, но большая часть не включенного кода — это просто создание элементов. Ошибка указывает, что в этом порядке переменная elements не может быть доступна до инициализации. И, как это заявлено, я могу только предположить (а также подкрепить точками останова, чтобы увидеть порядок выполнения), что он обращается к функции setElements() через событие, прежде чем читать что-либо из файла 1.js (что, кстати, это файл ConstantsAndGlobalVars.js, в котором я храню все свои константы и методы получения/установки.)

Leigh Hobson 08.05.2024 16:28

Я добавил ссылку на репозиторий GitHub в пост, как и сейчас, если у кого-то есть время запустить его, просто чтобы посмотреть. github.com/leighhobson89/ChipshopChopper

Leigh Hobson 08.05.2024 16:42

Сначала вам следует удалить циклы. Следует избегать циклических зависимостей.

morganney 08.05.2024 17:46

@somethinghere Почему ты так думаешь? Я протестировал его, и Chrome, похоже, не создает параллельные графы модулей, а сводит их в один большой граф, где каждый модуль инициализируется только один раз, как я и ожидал.

Tamas Hegedus 08.05.2024 18:23

Странно, я был уверен, что так и было раньше. Только что протестировал его, и он действительно делает это иначе, чем я использовал. Приятно это знать, но это немного странно, клянусь, из-за этого я уже сталкивался с подобной проблемой. Ах хорошо.

somethinghere 08.05.2024 18:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
11
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо за ссылку на репозиторий GitHub, таким образом я смог воспроизвести вашу проблему.

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

function main() {
  document.addEventListener('titleScreenCreated', settlements);
  const titleScreenCreatedEvent = new Event('titleScreenCreated');
  createGameWindow(titleScreenCreatedEvent);
  createTitleScreen();

  gameLoop();
}

document.addEventListener('DOMContentLoaded', () => {
  main();
});

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

Проблема решена и получен хороший урок! Отлично, спасибо за помощь!

Leigh Hobson 08.05.2024 19:02

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