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

按依赖顺序加载类:自定义Depends实现是否有更标准方案?

问题描述

我希望按依赖顺序加载类,让可扩展类先于继承它的类加载。以下实现方案可以正常工作,但对于这类常见需求来说似乎有些复杂。请问是否存在更标准的实现方式?

当前实现代码

使用方式

const depends = new Depends(LoadDepends);
depends.add("markerClass.js", []);
depends.add("zcla_clusters.js", ["markerClass.js"]);
depends.add("users.js", ["markerClass.js"]);
depends.add("zcla_wkcomsh.js", ["markerClass.js"]);
depends.chain();

自定义的Depends类

class Depends {
/**
 * 构造函数,创建Depends实例
 * @param {Function} onHasDepends - 所有依赖加载完成后执行的回调函数
 */
constructor(onHasDepends) {
    this._depends = [];
    this._loaded = [];
    this._loading = [];
    this._onHasDepends = onHasDepends;
}

/**
 * 添加依赖项
 * @param {string} name - 依赖项名称
 * @param {Array<string>} dependencies - 该依赖项的前置依赖数组
 */
add(name, dependencies) {
    if(!this._depends.includes(name)) {
        this._depends.push(name)
        this._depends[name] = dependencies;
        for(let i in dependencies) {
            if(!this._depends.includes(dependencies[i])) {
                alert("依赖 ["+ dependencies[i] +"] 未找到,无法添加 ["+ name +"]");
            }
        }
    }
}

/**
 * 检查指定模块的所有依赖是否已加载
 * @param {string} name - 模块名称
 * @returns {boolean} - 所有依赖已加载返回true,否则返回false
 */
depLoaded(name) {
    let f = true;
    for (let d = 0; d < this._depends[name].length; d++) {
        if (!this._loaded.includes(this._depends[name][d])) {
            f = false;
            break;
        }
    }
    return f;
}

/**
 * 检查所有依赖项是否已加载完成
 * @returns {boolean} - 所有依赖已加载返回true,否则返回false
 */
allLoaded() {
    let f = true;
    for (let i = 0; i < this._depends.length; i++) {
        if (!this._loaded.includes(this._depends[i])) {
            f = false;
            break;
        }
    }
    return f;
}

/**
 * 启动依赖链加载
 */
chain() {
    const ch = this;
    for (let i = 0; i < this._depends.length; i++) {
        if (!this._loading.includes(this._depends[i]) && this.depLoaded(this._depends[i])) {
            const script = document.createElement('script');
            script.src = 'javascripts/' + ch._depends[i];
            script.onload = function(){
                ch._loaded.push(this.src.split('/').pop());
                if (ch.allLoaded()) {
                    ch._onHasDepends();
                } else {
                    ch.chain();
                }
            };
            ch._loading.push(ch._depends[i]);
            document.head.appendChild(script);
        }
    }
}
}
标准实现方案

1. 使用ES原生模块(推荐)

现代浏览器和Node.js都原生支持ES模块,完全不需要自定义依赖加载逻辑,步骤如下:

  • 在HTML中加载入口脚本时添加type="module"属性:
<script type="module" src="javascripts/main.js"></script>
  • 在各个JS文件中用import和export声明依赖关系:
    比如markerClass.js作为基类:
export default class MarkerClass {
  // 类实现
}

zcla_clusters.js中导入依赖并实现子类:

import MarkerClass from './markerClass.js';

export default class ZclaClusters extends MarkerClass {
  // 子类实现
}

users.js同理:

import MarkerClass from './markerClass.js';

export default class Users extends MarkerClass {
  // 类实现
}

最后在入口文件main.js中导入所有需要的模块,浏览器会自动按依赖顺序加载:

import ZclaClusters from './zcla_clusters.js';
import Users from './users.js';
import ZclaWkcomsh from './zcla_wkcomsh.js';

// 对应原来的LoadDepends函数,所有模块加载完成后执行初始化
function LoadDepends() {
  // 初始化操作
}
LoadDepends();

ES模块会自动处理依赖解析、顺序加载,还支持异步加载、树摇等特性,是目前最标准的方案。

2. 使用模块打包工具(适合生产环境)

如果需要兼容旧浏览器或做打包优化,可使用Webpack、Rollup、Vite这类工具:

  • 代码编写依然用ES模块语法
  • 配置打包工具将所有模块打包成单个或多个bundle文件
  • 最终在HTML中引入打包后的文件即可,工具会自动处理依赖顺序和兼容性

3. 原生动态import()(按需加载场景)

如果需要按需加载模块,可使用原生import()函数,它返回Promise,能灵活控制加载顺序:

// 先加载基础依赖
import('./markerClass.js')
  .then(() => {
    // 依赖加载完成后,并行加载所有依赖它的模块
    return Promise.all([
      import('./zcla_clusters.js'),
      import('./users.js'),
      import('./zcla_wkcomsh.js')
    ]);
  })
  .then(() => {
    // 所有模块加载完成,执行回调
    LoadDepends();
  })
  .catch(err => console.error('加载失败:', err));

这种方式无需自定义类,利用原生Promise就能实现依赖顺序控制,代码更简洁。


内容的提问来源于stack exchange,提问作者Simon Barnett

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:44:50