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
相关产品推荐
相关产品推荐

