zoukankan      html  css  js  c++  java
  • seajs 源码分析三

    这次是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 fetched
    10   FETCHING: 1,
    11   // 2 - The meta data has been saved to cachedMods
    12   SAVED: 2,
    13   // 3 - The `module.dependencies` are being loaded
    14   LOADING: 3,
    15   // 4 - The module are ready to execute
    16   LOADED: 4,
    17   // 5 - The module is being executed
    18   EXECUTING: 5,
    19   // 6 - The `module.exports` is available
    20   EXECUTED: 6
    21 }

    接下来的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.dependencies
    Module.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
    }
    // 抓取一个module
    Module.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转化为uri
    Module.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
      }
    }
    
    // 新建或取得一个module
    Module.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 API
    
    seajs.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 Developers
    
    seajs.Module = Module
    data.fetchedList = fetchedList
    data.cid = cid
    
    seajs.require = function(id) {
      var mod = Module.get(Module.resolve(id))
      if (mod.status < STATUS.EXECUTING) {
        mod.onload()
        mod.exec()
      }
      return mod.exports
    }

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

  • 相关阅读:
    C# 哈希表
    C# 连接SQL Server数据库的连接字符串<转>
    C# ADO.NET中的五个主要对象<转>
    C# integrated security=SSPI<转>
    C# ADO.NET访问SQL Server数据库<转>
    C# .NET 页面间传值的几种方法<转>
    C# Datatable删除行的Delete和Remove方法
    C# DataTable转json
    CSP2019 爆炸记
    停更通知
  • 原文地址:https://www.cnblogs.com/cyITtech/p/3618723.html
Copyright © 2011-2022 走看看