JS多模块项目中Fetch、Promise与Alphabet类封装架构问题求解
方案实现
JS本身支持静态异步方法,之前的认知偏差是导致问题的核心原因,以下是完全符合需求的实现:
1. 改写alphabet.js模块
只默认导出Alphabet类,所有数据加载、实例初始化逻辑全部封装在模块内部:
// alphabet.js // 模块内部工具函数,不对外暴露 function getData(url) { return fetch(url).then(response => response.json()); } export default class Alphabet { // 存储所有初始化完成的Alphabet实例 static instances = {}; // 存储初始化Promise,避免重复调用init触发重复请求 static #initPromise = null; static calculateFrequency(letters, dict) { let freq = [] letters.forEach(letter => freq.push(Object.keys(dict).filter(word => word.startsWith(letter)).length)); return freq; } // 静态异步初始化方法,支持Alphabet.init调用逻辑 static async init() { // 已经初始化过直接返回实例 if (this.#initPromise) return this.#initPromise; this.#initPromise = (async () => { const json = await getData('alphabets.json'); for (const lang in json) { const dict = await getData(`dict/dict-${lang}.json`); this.instances[lang] = new Alphabet( lang, json[lang].name, dict, json[lang].alphabet, json[lang].rtl ); } return this.instances; })(); return this.#initPromise; } constructor(lang, name, dict, alphabet, rtl=false) { this.lang = lang; this.dict = dict; this.letters = alphabet.split(''); this.name = name; this.rtl = rtl; this.frequency = Alphabet.calculateFrequency(this.letters, this.dict); this.maxFrequency = Math.max(...this.frequency); } }
2. 入口app.js调用方式
// app.js import Alphabet from './alphabet.js'; async function main() { // 触发初始化,拿到所有实例 const alphabets = await Alphabet.init(); // 继续后续应用初始化逻辑 console.log('所有Alphabet实例:', alphabets); } window.addEventListener('load', main);
3. 其他模块使用逻辑
任意需要访问Alphabet类、实例的地方,直接导入默认导出的类即可:
// 任意业务模块 import Alphabet from './alphabet.js'; // 直接访问所有已初始化的实例 console.log(Alphabet.instances); // 调用类的静态方法 console.log(Alphabet.calculateFrequency(['a','b'], {"a":1, "ab":2, "c":3}));
方案优势
- 完全符合要求:模块仅对外默认导出Alphabet一个类,无额外导出
- 加载逻辑全封装在Alphabet类内部,高内聚低耦合
- 自带防重复初始化逻辑,多次调用Alphabet.init也不会重复发起网络请求
- 所有静态方法、实例集合都挂载在Alphabet类上,任意模块导入即可直接访问
内容的提问来源于stack exchange,提问作者Cirrocumulus
相关产品推荐
相关产品推荐

