站点工具

用户工具


手写模块加载器

需求

一个模块加载器一般来说会在全局暴露出 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)

以上代码为模块加载器的简易实现,未涉及模块的网络下载以及循环引用的处理。

若愚 · 2021/09/27 11:44 · javascript_手写模块加载器.txt