背景
以下是手写系列内容预告,初步计划一周一个主题。
- 手写Promise、Promise.all、Promise.race
- 手写发布订阅模式
- 手写简易Redux
- 手写简易模块加载器
- 手写简易模块打包器
- 手写简易React
- 手写简易React Hooks
- ......(根据小伙伴的提议待定)
需求
一个模块加载器一般来说会在全局暴露出 define 和 require 两个函数。
define用来定义一个模块,其参数为:当前的模块名、依赖的模块名列表、当前模块的实现。
require用来加载并执行模块,其参数为:运行依赖的模块名列表、当前要执行的函数。
为此,我们需要对 define和requrie进行实现,以实现如下调用。
function define(name, deps, callback) {
// todo...
}
function require(deps, callback) {
// todo...
}
define('firstName', [], () => {
return '饥人谷'
})
define('lastName', [], () => {
return '前端'
})
define('sayHello', ['firstName', 'lastName'], (v1, v2) => {
return function() {
console.log(`Hello ${v1} ${v2}`)
}
})
require(['sayHello'], (fn) => {
fn()
})
简易模块加载器雏形
let modules = {}
function define(name, deps, callback) {
depFns = deps.map(depName => modules[depName])
modules[name] = callback.apply(null, depFns)
}
function require(deps, callback) {
depFns = deps.map(depName => modules[depName])
callback.apply(null, depFns)
}
实现原理为:当定义一个模块时,先从依赖的模块名列表得到这些依赖的模块的函数实现构成的数组,给modules添加一个属性,其值为模块实现执行后的结果,其参数为依赖的模块实现函数数组。
优化
(global => {
let modules = {}
function require(deps, callback) {
if(!Array.isArray(deps)) {
callback = deps
deps = []
}
depFns = deps.map(depName => modules[depName])
return callback.apply(null, depFns)
}
function define(name, deps, callback) {
modules[name] = require(deps, callback)
}
global.define = define
global.require = require
})(window)
以上代码为模块加载器的简易实现,未涉及模块的网络下载以及循环引用的处理。