You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript模块加载顺序问题:如何强制指定文件执行先后

问题描述

没法让一个.js文件的代码在另一个文件执行前跑完。核心问题是:在2.js里通过dispatch事件调用1.js里的函数,事件触发时确实调用到了这个函数,但函数要赋值的变量(在1.js里声明在函数上方)返回undefined。

试过在2.js触发事件前声明这个变量并导出,但报“无法给常量变量赋值”的错。想把这个变量单独放在一个文件里,因为它是一长串DOM元素列表,不想每次修改元素innerHTML时都调用document.getElementById(),所以用事件触发函数,想在元素创建后、修改前完成它的初始化。

需要一种方法,不用defer、调整HTML脚本顺序或者把脚本放<head>标签里(这些方法都试过没用),强制让1.js里的变量在2.js执行任何操作前完成初始化。

已尝试的方法:

  • 用defer让1.js在2.js前加载
  • 把1.js放在<head>标签中
  • 在设置elements变量的函数里创建Promise,当elements不为null或undefined时resolve(但对异步编程不熟,可能实现错了)
  • 调整HTML中<script>标签的顺序

代码示例

1.js

let elements;

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

// 补充:原代码中提到的getElements函数(用户代码遗漏,推测实现如下)
export function getElements() {
  return elements;
}

2.js

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

document.addEventListener('titleScreenCreated', setElements);
const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
// 创建各类元素的代码
document.dispatchEvent(titleScreenCreatedEvent);
console.log(getElements());
// 修改元素的代码
// 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>

解决方案

方法1:Promise封装初始化,等待完成后执行后续代码

修改1.js,用Promise标记初始化完成,提供等待方法:

let elements;
let initResolve;

// 初始化Promise,等待元素设置完成
const elementsReady = new Promise(resolve => {
  initResolve = resolve;
});

export function setElements() {
  elements = {
    option1: document.getElementById('option1'),
    option2: document.getElementById('option2'),
    // etc
  };
  initResolve(); // 标记初始化完成
}

export function getElements() {
  return elements;
}

export async function waitForElements() {
  await elementsReady;
  return elements;
}

修改2.js,等待元素初始化完成后再操作:

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

document.addEventListener('titleScreenCreated', setElements);
const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
// 创建各类元素的代码
document.dispatchEvent(titleScreenCreatedEvent);

// 用自执行异步函数等待初始化
(async () => {
  const elements = await waitForElements();
  console.log(elements);
  elements.option1.innerHTML = "hello world";
})();

方法2:回调函数替代事件监听

直接在setElements中传入回调,初始化完成后立即执行后续逻辑:

修改1.js:

let elements;

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

export function getElements() {
  return elements;
}

修改2.js:

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

const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
// 创建各类元素的代码

// 直接调用setElements并传入后续操作的回调
setElements((elements) => {
  console.log(elements);
  elements.option1.innerHTML = "hello world";
});

内容的提问来源于stack exchange,提问作者Leigh Hobson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 13:44:53