实现 JS 的 AMD 模块加载器

AMD是解决JS模块化的规范,实现这样的一个模块加载器的关键在于解决每个模块依赖的解析。

use 入口、[]存放主模块依赖、使用对象保存模块属性

for 依赖

config 保存路径

loadModule() 加载模块、判断是否加载过该模块

首先我们需要有一个模块的入口,也就是主模块,比如我们使用 一个 use 方法作为入口,之后以数组的形式列出了主模块的依赖,

这时候我们要想到的是如何解析这一个一个的依赖,也就是如何解析出一个个js文件的绝对地址, 我们可以制定一个规则,如默认为主模块的路径为基准,也可以像 requirejs 一样使用一个config方法来指定一个baseurl和为每一个模块指定一个path,

其中每个模块的代码都应该在依赖加载完之后执行,这就是一个 回调函数,模块的依赖、回调函数、状态、名字、模块导出等可以看做是一个模块的属性,因此我们可以使用一个对象来保存所有的模块,然后每个模块的各个属性存放在一个对象中。

最后我们来考虑一下模块加载的问题,上面我们说到use方法,use方法的逻辑就是遍历依赖,然后对每个模块进行加载,也就是解析地址然后使用插入script,

我们假设 使用loadModule方法来加载依赖,那么这个函数的逻辑就应该是检查我们的模块是否已经加载过,判断是否需要加载,

loadModule 方法执行依赖的方式是创建 script 标签添加到页面中,在标签 onload 或者 onreadystatechange 发生改变时 && readyState === "complete“ 执行 callback

如果这个模块还有依赖则调用use方法继续解析,模块依赖中我们 还没有提到的问题就是每个模块的依赖是需要被传进模块里来使用的,解决方法就是每个模块的callback方法执行后的返回的export记录下来然后使用apply之类的方法将这些参数传递进去。

我们需要暴露一个 define 方法来定义模块,也就是模块名,依赖以及每个模块的各自代码。

来源整理自:vue3js.cn 面试官系列