跨模块调用函数时遭遇Uncaught ReferenceError错误求助
问题:模块变量未初始化导致的引用错误
模块代码
database.js
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js"; import { getFirestore, collection, getDocs } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-firestore-lite.js"; import { getAuth } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-auth.js"; const firebaseConfig = { // 配置信息 }; // 初始化Firebase const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); let usersListTmp = []; async function getUsersListFromDB() { if (usersListTmp.length == 0) { // 此处报错! await getDocs(collection(db, "users")).then((usersSnapshot) => { usersSnapshot.forEach((value) => { usersListTmp.push(value.data()); }); }); } return usersListTmp; } export { getUsersListFromDB }
common.js
import { getUsersListFromDB } from "../database/database.js"; let usersList = await getUsersListFromDB(); // 此处调用函数 console.log(usersList); function getUsersList() { return usersList; } function setUsersList(list) { usersList = list; } export { getUsersList, setUsersList }
input_data.js
import { registerUser, getUsersListFromDB } from "../database/database.js"; import { getUsersList } from "../js/common.js" let usersList = getUsersList(); // 此处为初始函数调用 console.log(usersList);
错误信息
在common.js调用getUsersListFromDB()时触发:
Uncaught ReferenceError: can't access lexical declaration 'usersListTmp' before initialization
调整代码后,firebaseConfig、app、auth、db也出现相同的未初始化错误。
补充:全局变量均未初始化,仅在函数调用时执行函数逻辑,未完成全局变量初始化。
需求
保证usersListTmp仅在database.js模块内访问,同时解决变量未初始化的错误。
解决方案
1. 修复顶级await导致的执行顺序问题
common.js中的顶级await会阻塞模块加载,可能导致database.js未完成变量初始化就被调用。将初始化逻辑封装到异步函数中:
import { getUsersListFromDB } from "../database/database.js"; let usersList = []; async function initUsersList() { usersList = await getUsersListFromDB(); console.log(usersList); } initUsersList(); function getUsersList() { return usersList; } function setUsersList(list) { usersList = list; } export { getUsersList, setUsersList, initUsersList // 可选:导出初始化函数,供主模块等待加载完成 }
2. 封装私有变量确保初始化顺序
用IIFE封装usersListTmp,既保证变量私有,又确保初始化逻辑优先执行:
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js"; import { getFirestore, collection, getDocs } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-firestore-lite.js"; import { getAuth } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-auth.js"; const firebaseConfig = { // 配置信息 }; // 初始化Firebase实例 const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); // IIFE封装私有变量和函数,确保变量先初始化再被访问 const getUsersListFromDB = (() => { let usersListTmp = []; return async function() { if (usersListTmp.length === 0) { // 替换then为await,简化代码逻辑 const usersSnapshot = await getDocs(collection(db, "users")); usersSnapshot.forEach((value) => { usersListTmp.push(value.data()); }); } return usersListTmp; }; })(); export { getUsersListFromDB }
3. 主模块等待初始化完成
若需要确保usersList加载完成后再使用,在input_data.js中等待初始化:
import { getUsersList, initUsersList } from "../js/common.js" async function main() { await initUsersList(); let usersList = getUsersList(); console.log(usersList); } main();
错误原因
- 顶级
await会让模块进入等待状态,打乱依赖模块的初始化顺序,导致函数访问变量时变量未完成初始化。 - 模块加载的执行顺序因顶级
await被干扰,触发“无法在初始化前访问词法声明”的错误。
内容的提问来源于stack exchange,提问作者Al-Jaabir
相关产品推荐
相关产品推荐

