博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
seajs 源码分析三
阅读量:5462 次
发布时间:2019-06-15

本文共 7552 字,大约阅读时间需要 25 分钟。

这次是seajs源码分析的倒数第二篇,因为涉及到后面的代码运行分析,所以比较长(终于要写一篇超长博客了。。。)

首先还是和以前一样,对seajs的源码进行分析

先是一系列的变量,这些是在seajs中的全局变量,用于储存一些要加载或加载完的js,css文件的module,还有加载的状态,源码如下:

1 var cachedMods = seajs.cache = {} 2 var anonymousMeta 3  4 var fetchingList = {} 5 var fetchedList = {} 6 var callbackList = {} 7  8 var STATUS = Module.STATUS = { 9   // 1 - The `module.uri` is being fetched10   FETCHING: 1,11   // 2 - The meta data has been saved to cachedMods12   SAVED: 2,13   // 3 - The `module.dependencies` are being loaded14   LOADING: 3,15   // 4 - The module are ready to execute16   LOADED: 4,17   // 5 - The module is being executed18   EXECUTING: 5,19   // 6 - The `module.exports` is available20   EXECUTED: 621 }

接下来的Module构造函数就是加载js,css的核心函数,通过一些列的处理,实现文件的加载,加载过程中调用顺序在最后讲

function Module(uri, deps) {  this.uri = uri  this.dependencies = deps || []  this.exports = null  this.status = 0  // 哪些依赖自己  this._waitings = {}  // 还未加载的依赖文件数  this._remain = 0}
Module.prototype.resolve = function() {  var mod = this  var ids = mod.dependencies  var uris = []  // 用循环将每个依赖文件路径整理出来,放入uris中  for (var i = 0, len = ids.length; i < len; i++) {    uris[i] = Module.resolve(ids[i], mod.uri)  }  return uris}
// 加载module.dependenciesModule.prototype.load = function() {  var mod = this  // 如果这个module已经在加载了,那么就等待onload运行  if (mod.status >= STATUS.LOADING) {    return  }  mod.status = STATUS.LOADING  // 运行load事件  var uris = mod.resolve()  emit("load", uris)  var len = mod._remain = uris.length  var m  // 初始化module并且在waitings中注册  for (var i = 0; i < len; i++) {    m = Module.get(uris[i])    if (m.status < STATUS.LOADED) {      // 注意:这里可能不止一次的需求,所以不应该一直是1      m._waitings[mod.uri] = (m._waitings[mod.uri] || 0) + 1    }    else {      mod._remain--    }  }  if (mod._remain === 0) {    mod.onload()    return  }  // 开始加载依赖的文件  var requestCache = {}  for (i = 0; i < len; i++) {    m = cachedMods[uris[i]]    if (m.status < STATUS.FETCHING) {      m.fetch(requestCache)    }    else if (m.status === STATUS.SAVED) {      m.load()    }  }  // 在最后一起发出请求,防止IE下的bug发生. Issues#808  for (var requestUri in requestCache) {    if (requestCache.hasOwnProperty(requestUri)) {      requestCache[requestUri]()    }  }}// 在module加载完成后,运行此函数Module.prototype.onload = function() {  var mod = this  mod.status = STATUS.LOADED  if (mod.callback) {    mod.callback()  }  // 让那些需要这个文件的文件module在remain ===0的情况下运行onload  var waitings = mod._waitings  var uri, m  for (uri in waitings) {    if (waitings.hasOwnProperty(uri)) {      m = cachedMods[uri]      // 注意减的数不是1,与上面设置对应      m._remain -= waitings[uri]      if (m._remain === 0) {        m.onload()      }    }  }  //减少空间占用  delete mod._waitings  delete mod._remain}
// 抓取一个moduleModule.prototype.fetch = function(requestCache) {  var mod = this  var uri = mod.uri  mod.status = STATUS.FETCHING  // 运行fetch事件  var emitData = { uri: uri }  emit("fetch", emitData)  var requestUri = emitData.requestUri || uri  // 对于无uri情况  if (!requestUri || fetchedList[requestUri]) {    mod.load()    return  } // 如果fetchingList已经有了,那么将这个mod推入,然后等待即可  if (fetchingList[requestUri]) {    callbackList[requestUri].push(mod)    return  }  fetchingList[requestUri] = true  callbackList[requestUri] = [mod]  // 运行request事件  emit("request", emitData = {    uri: uri,    requestUri: requestUri,    onRequest: onRequest,    charset: data.charset  })  if (!emitData.requested) {    requestCache ?        requestCache[emitData.requestUri] = sendRequest :        sendRequest()  }  function sendRequest() {    seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)  }  function onRequest() {    delete fetchingList[requestUri]    fetchedList[requestUri] = true    // 为匿名module保存meta数据    if (anonymousMeta) {      Module.save(uri, anonymousMeta)      anonymousMeta = null    }    // 运行callback    var m, mods = callbackList[requestUri]    delete callbackList[requestUri]    while ((m = mods.shift())) m.load()  }}
// 运行module中的代码Module.prototype.exec = function () {  var mod = this  // 当一个module已经运行过了,那么跳过  // 防止循环不断运行  if (mod.status >= STATUS.EXECUTING) {    return mod.exports  }  mod.status = STATUS.EXECUTING  // require函数  var uri = mod.uri  function require(id) {    return Module.get(require.resolve(id)).exec()  }  require.resolve = function(id) {    return Module.resolve(id, uri)  }  require.async = function(ids, callback) {    Module.use(ids, callback, uri + "_async_" + cid())    return require  }  // 运行factory函数  // factory会在define中设置  var factory = mod.factory  var exports = isFunction(factory) ?      factory(require, mod.exports = {}, mod) :      factory  if (exports === undefined) {    exports = mod.exports  }  // 较少内存消耗  delete mod.factory  mod.exports = exports  mod.status = STATUS.EXECUTED  // 执行exec事件  emit("exec", mod)  return exports}
// 将id转化为uriModule.resolve = function(id, refUri) {  // 激发resolve事件  var emitData = { id: id, refUri: refUri }  emit("resolve", emitData)  // 调用的是seajs.resolve  return emitData.uri || seajs.resolve(emitData.id, refUri)}// define函数,这个函数会被暴露到全局Module.define = function (id, deps, factory) {  var argsLen = arguments.length  // 只有工厂函数的情况  if (argsLen === 1) {    factory = id    id = undefined  }  else if (argsLen === 2) {    factory = deps    // define(deps, factory)    if (isArray(id)) {      deps = id      id = undefined    }    // define(id, factory)    else {      deps = undefined    }  }  // 通过分析factory的代码,得到需要加载的文件  // 全文正则分析  if (!isArray(deps) && isFunction(factory)) {    deps = parseDependencies(factory.toString())  }  var meta = {    id: id,    uri: Module.resolve(id),    deps: deps,    factory: factory  }  // 对于匿名的module,尝试着从currentScript拿到uri  if (!meta.uri && doc.attachEvent) {    var script = getCurrentScript()    if (script) {      meta.uri = script.src    }  }  // 激发define事件  emit("define", meta)  meta.uri ? Module.save(meta.uri, meta) :      // 储存信息      anonymousMeta = meta}
// 将meta中的内容存到已缓存的module中Module.save = function(uri, meta) {  var mod = Module.get(uri)  // 绝不覆盖已经存储过的module  if (mod.status < STATUS.SAVED) {    mod.id = meta.id || uri    mod.dependencies = meta.deps || []    mod.factory = meta.factory    mod.status = STATUS.SAVED  }}// 新建或取得一个moduleModule.get = function(uri, deps) {  return cachedMods[uri] || (cachedMods[uri] = new Module(uri, deps))}// 加载的函数Module.use = function (ids, callback, uri) {  var mod = Module.get(uri, isArray(ids) ? ids : [ids])  // mod的callback在这里添加  mod.callback = function() {    var exports = []    var uris = mod.resolve()    for (var i = 0, len = uris.length; i < len; i++) {      exports[i] = cachedMods[uris[i]].exec()    }    if (callback) {      callback.apply(global, exports)    }    delete mod.callback  }  mod.load()}//在所有其他module先加载预加载模块Module.preload = function(callback) {  var preloadMods = data.preload  var len = preloadMods.length  if (len) {    Module.use(preloadMods, function() {      // 移除已经加载的预加载模块      preloadMods.splice(0, len)      Module.preload(callback)    }, data.cwd + "_preload_" + cid())  }  else {    callback()  }}// Public APIseajs.use = function(ids, callback) {  Module.preload(function() {    Module.use(ids, callback, data.cwd + "_use_" + cid())  })  return seajs}Module.define.cmd = {}// 将define暴露到全局global.define = Module.define// For Developersseajs.Module = Moduledata.fetchedList = fetchedListdata.cid = cidseajs.require = function(id) {  var mod = Module.get(Module.resolve(id))  if (mod.status < STATUS.EXECUTING) {    mod.onload()    mod.exec()  }  return mod.exports}

 写到后面才发现,原来这块的源码那么长,默默的决定再开一篇把剩下的运行顺序写写完。

 

 

 

 

 

转载于:https://www.cnblogs.com/cyITtech/p/3618723.html

你可能感兴趣的文章
P4302 [SCOI2003]字符串折叠
查看>>
神秘的程序员
查看>>
jS 中创建对象:
查看>>
zless轻量级样式框架
查看>>
ZeroMQ接口函数之 :zmq_term - 终结ZMQ环境上下文(context)
查看>>
js获取倒计时
查看>>
loadrunner安装过程中的,注册表问题
查看>>
git push失败the remote end hung up unexpectedly
查看>>
POJ3087 Shuffle'm Up 简单模拟
查看>>
Django中数据的增删改查
查看>>
iOS模拟器发生了崩溃,去哪找Crash Log
查看>>
[支付宝]即时到账接口对接总结
查看>>
夺命雷公狗-----React---15--三元运算符
查看>>
元首的愤怒 SharePoint Apps
查看>>
CSS
查看>>
两个DataGrid垂直滚动条同步滚动
查看>>
RPG的错排
查看>>
Java 7之基础 - 强引用、弱引用、软引用、虚引用
查看>>
位运算
查看>>
微软源代码管理工具TFS2013安装与使用图文教程
查看>>