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

    继续接上一篇来分享剩下的seajs源码,计划这一篇写完以后再来一篇就结束了。这一篇就是分析moudle之前的部分

    首先是前面的一些变量声明

     1 var doc = document
     2 var cwd = dirname(doc.URL)
     3 var scripts = doc.scripts
     4 
     5 // 默认的是seajsnode作为id添加到dom中,或者作为script里最后一个项添加到dom中
     6 var loaderScript = doc.getElementById("seajsnode") ||
     7     scripts[scripts.length - 1]
     8 
     9 // 如果seajs正在工作时,取得正在执行的script的路径,或者取得cwd
    10 var loaderDir = dirname(getScriptAbsoluteSrc(loaderScript) || cwd)
    11 
    12 function getScriptAbsoluteSrc(node) {
    13   return node.hasAttribute ? // IE6/7下没有
    14       node.src :
    15     // 详细属性见 http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
    16       node.getAttribute("src", 4)
    17 }
    18 
    19 
    20 // 开发测试用
    21 seajs.resolve = id2Uri

    下面这段开始是在util-request.js中

    1 var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement
    2 var baseElement = head.getElementsByTagName("base")[0]
    3 
    4 var IS_CSS_RE = /.css(?:?|$)/i
    5 var currentlyAddingScript
    6 var interactiveScript

    由于onload在webkit小于535.23和firefox小于9.0版本下是不支持onload事件的,所以要做一些额外处理。

    1 var isOldWebKit = +navigator.userAgent
    2     .replace(/.*(?:AppleWebKit|AndroidWebKit)/(d+)..*/, "$1") < 536

    isOldWebkit 是用来确定webkit的版本号是否过于陈旧,这样用这个变量就可以额外在最后onload事件设置中做一些额外处理。

    接下去的源码如下:

     1 function request(url, callback, charset) {
     2   var isCSS = IS_CSS_RE.test(url)
     3   var node = doc.createElement(isCSS ? "link" : "script")
     4 
     5   if (charset) {
     6     var cs = isFunction(charset) ? charset(url) : charset
     7     if (cs) {
     8       node.charset = cs
     9     }
    10   }
    11   
    12   // 添加onload
    13   addOnload(node, callback, isCSS, url)
    14   
    15   // 根据添加类型不同,增加不同属性
    16   if (isCSS) {
    17     node.rel = "stylesheet"
    18     node.href = url
    19   }
    20   else {
    21     node.async = true
    22     node.src = url
    23   }
    24 
    25   // 在IE6-8中,在insert以后script会立刻执行
    26   // 所以用currentlyAddingScript来维持住,用于在define中取得url
    27 
    28   // ref: #185 & http://dev.jquery.com/ticket/2709
    29   baseElement ?
    30       head.insertBefore(node, baseElement) :
    31       head.appendChild(node)
    32 
    33   currentlyAddingScript = null
    34 }

    上面讲到的addOnload函数在下面分析,其中有node=null,这是考虑到IE下的变量销毁机制而设置的,可以有效减少内存使用

    function addOnload(node, callback, isCSS, url) {
      var supportOnload = "onload" in node
    
      // 在webkit和firefox的老版本中
      if (isCSS && (isOldWebKit || !supportOnload)) {
        setTimeout(function() {
          pollCss(node, callback)
        }, 1) // 在node加入之后就开始执行
        return
      }
    
      if (supportOnload) {
        node.onload = onload
        node.onerror = function() {
          emit("error", { uri: url, node: node })    // 触发error自定义事件
          onload()
        }
      }
      else {
        // 不支持onload的情况下,借助onreadystatechange
        node.onreadystatechange = function() {
          if (/loaded|complete/.test(node.readyState)) {
            onload()
          }
        }
      }
    
      function onload() {
        // 确保只运行一次,防止内存泄露
        node.onload = node.onerror = node.onreadystatechange = null
    
        // 移除script
        if (!isCSS && !data.debug) {
          head.removeChild(node)
        }
    
        node = null
    
        callback()
      }
    }

    对于是css的情况,通过检测sheet来辨别是否成功加载

    function pollCss(node, callback) {
      var sheet = node.sheet
      var isLoaded
    
      // 对于WebKit < 536
      if (isOldWebKit) {
        if (sheet) {
          isLoaded = true
        }
      }
    
      else if (sheet) {
        try {
          if (sheet.cssRules) {
            isLoaded = true
          }
        } catch (ex) {
          // 在 Firefox 13.0 以后`ex.name`的值从 "NS_ERROR_DOM_SECURITY_ERR"
          // 变为 "SecurityError" 但是我们这里只要测试小于9.0版本,所以不要紧
          if (ex.name === "NS_ERROR_DOM_SECURITY_ERR") {
            isLoaded = true
          }
        }
      }
    
      setTimeout(function() {
        if (isLoaded) {
          // 在这里执行callback 让css有够的时间运行
          callback()
        }
        else {
          pollCss(node, callback)
        }
      }, 20)
    }

    关于下面的require的正则匹配,太长了。。。没有好好读,待我研究一番

    // 取得正在操作的script
    function getCurrentScript() {
      if (currentlyAddingScript) {
        return currentlyAddingScript
      }
    
      // 在 IE6-9 的浏览器中,onload事件可能不会正确运行
      // 但是,我们可以认为,在script node中属性是interactive的状态时,就是正在运行的script
      // interactive在前面有声明,是seajs闭包中的全局变量
      if (interactiveScript && interactiveScript.readyState === "interactive") {
        return interactiveScript
      }
    
      var scripts = head.getElementsByTagName("script")
    
      for (var i = scripts.length - 1; i >= 0; i--) {
        var script = scripts[i]
        if (script.readyState === "interactive") {
          interactiveScript = script
          return interactiveScript
        }
      }
    }
    
    
    // 测试用
    seajs.request = request
    
    
    /**
     * util-deps.js - The parser for dependencies
     */
    
    // require的正则判断
    var REQUIRE_RE = /"(?:\"|[^"])*"|'(?:\'|[^'])*'|/*[Ss]*?*/|/(?:\/|[^/
    ])+/(?=[^/])|//.*|.s*require|(?:^|[^$])requires*(s*(["'])(.+?)1s*)/g
    var SLASH_RE = /\\/g
    
    function parseDependencies(code) {
      var ret = []
      // 首先搞定多个连在一起的情况,接下来就是require的匹配
      code.replace(SLASH_RE, "")
          .replace(REQUIRE_RE, function(m, m1, m2) {
            if (m2) {
              ret.push(m2)
            }
          })
    
      return ret
    }

    后面三到四天要出去旅游了(毕业旅行呦!),回来以后把最后一篇补上。最后一篇计划是写完上面类似的分析后,整理一个运行的步骤,不然会感觉好混乱好混乱。。。。

    呦,出去踏青喽!

  • 相关阅读:
    java 事件监听机制组成
    关于父进程和子进程的关系(UAC 绕过思路)
    Fort.js – 时尚、现代的进度提示效果
    Hive学习之函数DDL和Show、Describe语句
    js完美的div拖拽实例代码
    SSH2框架实现注冊发短信验证码实例
    再看C#中的托付和事件
    RGB(FFFFFF)转255:255:255
    单一目的聚集操作
    智慧城市,在中国的北海边再画一个圈——大连“中国首届智慧城市协同创新峰会”请你带好笔
  • 原文地址:https://www.cnblogs.com/cyITtech/p/3606217.html
Copyright © 2011-2022 走看看