那么调用这个factory的时候,exports就为module.exports,也是是字符串"main-moudle"。最后callback传入的参数就是"main-moudle"。所以我们执行最开头写的那段代码,最后会在页面上弹出main-moudle。
define定义模块
你以为到这里就结束了吗?并没有。前面只说了加载依赖模块中define方法中没有其他依赖,那如果有其他依赖呢?废话不多说,先看看define方法做了什么:
global.define = Module.define Module.define = function (id, deps, factory) { var argsLen = arguments.length // 参数校准 if (argsLen === 1) { factory = id id = undefined } else if (argsLen === 2) { factory = deps if (isArray(id)) { deps = id id = undefined } else { deps = undefined } } // 如果没有直接传入依赖数组 // 则从factory中提取所有的依赖模块到dep数组中 if (!isArray(deps) && isFunction(factory)) { deps = typeof parseDependencies === "undefined" ? [] : parseDependencies(factory.toString()) } var meta = { //模块加载与定义的元数据 id: id, uri: Module.resolve(id), deps: deps, factory: factory } // 激活define事件, used in nocache plugin, seajs node version etc emit("define", meta) meta.uri ? Module.save(meta.uri, meta) : // 在脚本加载完毕的onload事件进行save anonymousMeta = meta }
首先进行了参数的修正,这个逻辑很简单,直接跳过。第二步判断了有没有依赖数组,如果没有,就通过parseDependencies方法从factory中获取。这个方法很有意思,是一个状态机,会一步步的去解析字符串,匹配到require,将其中的模块取出,最后放到一个数组里。这个方法在requirejs中是通过正则实现的,早期seajs也是通过正则匹配的,后来改成了这种状态机的方式,可能是考虑到性能的问题。seajs的仓库中专门有一个模块来讲这个东西的,请看链接。
获取到依赖模块之后又设置了一个meta对象,这个就表示这个模块的原数据,里面有记录模块的依赖项、id、factory等。如果这个模块define的时候没有设置id,就表示是个匿名模块,那怎么才能与之前发起请求的那个mod相匹配呢?
这里就有了一个全局变量anonymousMeta,先将元数据放入这个对象。然后回过头看看模块加载时设置的onload函数里面有一段就是获取这个全局变量的。
function onRequest(error) { //模块加载完毕的回调 ... // 保存元数据到匿名模块,uri为请求js的uri if (anonymousMeta) { Module.save(uri, anonymousMeta) anonymousMeta = null } ... }
不管是不是匿名模块,最后都是通过save方法,将元数据存入到mod中。
// 存储元数据到 cachedMods 中 Module.save = function(uri, meta) { var mod = Module.get(uri) if (mod.status < STATUS.SAVED) { mod.id = meta.id || uri mod.dependencies = meta.deps || [] mod.factory = meta.factory mod.status = STATUS.SAVED } }
这里完成之后,就是和前面的逻辑一样了,先去校验当前模块有没有依赖项,如果有依赖项,就去加载依赖项和use的逻辑是一样的,等依赖项全部加载完毕后,通知入口模块的remain减1,知道remain为0,最后调用入口模块的回调方法。整个seajs的逻辑就已经全部走通,Yeah!
结语
有过看requirejs的经验,再来看seajs还是顺畅很多,对模块化的理解有了更加深刻的理解。阅读源码之前还是得对框架有个基本认识,并且有使用过,要不然很多地方都很懵懂。所以以后还是阅读一些工作中有经常使用的框架或类库的源码进行阅读,不能总像个无头苍蝇一样。
最后用一张流程图,总结下seajs的加载过程。
您可能感兴趣的文章: