【Seajs源碼分析】3. 工具方法2

util-request.js 動態加載模塊javascript

/**
 * util-request.js - The utilities for requesting script and style files
 * ref: tests/research/load-js-css/test.html
 */

var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement
var baseElement = head.getElementsByTagName("base")[0]

var IS_CSS_RE = /\.css(?:\?|$)/i
var currentlyAddingScript
var interactiveScript

// `onload` event is not supported in WebKit < 535.23 and Firefox < 9.0
// ref:
//  - https://bugs.webkit.org/show_activity.cgi?id=38995
//  - https://bugzilla.mozilla.org/show_bug.cgi?id=185236
//  - https://developer.mozilla.org/en/HTML/Element/link#Stylesheet_load_events
var isOldWebKit = +navigator.userAgent
    .replace(/.*AppleWebKit\/(\d+)\..*/, "$1") < 536


function request(url, callback, charset) {
  var isCSS = IS_CSS_RE.test(url)
  var node = doc.createElement(isCSS ? "link" : "script")

  if (charset) {
    var cs = isFunction(charset) ? charset(url) : charset
    if (cs) {
      node.charset = cs
    }
  }

  addOnload(node, callback, isCSS, url)

  if (isCSS) {
    node.rel = "stylesheet"
    node.href = url
  }
  else {
    node.async = true
    node.src = url
  }

  // For some cache cases in IE 6-8, the script executes IMMEDIATELY after
  // the end of the insert execution, so use `currentlyAddingScript` to
  // hold current node, for deriving url in `define` call
  currentlyAddingScript = node

  // ref: #185 & http://dev.jquery.com/ticket/2709
  baseElement ?
      head.insertBefore(node, baseElement) :
      head.appendChild(node)

  currentlyAddingScript = null
}

function addOnload(node, callback, isCSS, url) {
  var supportOnload = "onload" in node

  // for Old WebKit and Old Firefox
  if (isCSS && (isOldWebKit || !supportOnload)) {
    setTimeout(function() {
      pollCss(node, callback)
    }, 1) // Begin after node insertion
    return
  }

  if (supportOnload) {
    node.onload = onload
    node.onerror = function() {
      emit("error", { uri: url, node: node })
      onload()
    }
  }
  else {
    node.onreadystatechange = function() {
      if (/loaded|complete/.test(node.readyState)) {
        onload()
      }
    }
  }

  function onload() {
    // Ensure only run once and handle memory leak in IE
    node.onload = node.onerror = node.onreadystatechange = null

    // Remove the script to reduce memory leak
    if (!isCSS && !data.debug) {
      head.removeChild(node)
    }

    // Dereference the node
    node = null

    callback()
  }
}

function pollCss(node, callback) {
  var sheet = node.sheet
  var isLoaded

  // for WebKit < 536
  if (isOldWebKit) {
    if (sheet) {
      isLoaded = true
    }
  }
  // for Firefox < 9.0
  else if (sheet) {
    try {
      if (sheet.cssRules) {
        isLoaded = true
      }
    } catch (ex) {
      // The value of `ex.name` is changed from "NS_ERROR_DOM_SECURITY_ERR"
      // to "SecurityError" since Firefox 13.0. But Firefox is less than 9.0
      // in here, So it is ok to just rely on "NS_ERROR_DOM_SECURITY_ERR"
      if (ex.name === "NS_ERROR_DOM_SECURITY_ERR") {
        isLoaded = true
      }
    }
  }

  setTimeout(function() {
    if (isLoaded) {
      // Place callback here to give time for style rendering
      callback()
    }
    else {
      pollCss(node, callback)
    }
  }, 20)
}

function getCurrentScript() {
  if (currentlyAddingScript) {
    return currentlyAddingScript
  }

  // For IE6-9 browsers, the script onload event may not fire right
  // after the script is evaluated. Kris Zyp found that it
  // could query the script nodes and the one that is in "interactive"
  // mode indicates the current script
  // ref: http://goo.gl/JHfFW
  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
    }
  }
}


// For Developers
seajs.request = request

request函數:對url進行異步請求,請求完畢執行回調函數css

addOnload函數:設置載入完畢後的回調動做,根據css,js以及瀏覽器是不是老版本,是否支持onload事件等狀況進行區分處理,若是是css文件而且是老版本瀏覽器或者不支持onload,則使用一個定時器循環的來判斷css是否載入完成(pollCSS),若是是js而且支持onload和不支持onload分兩種狀況進行了處理,最終目的是載入資源文件後能及時回調函數html

pollCSS函數:判斷css文件是否載入完成的函數,若是沒有使用定時器不停的去判斷,直到載入完成。java

getCurrentScript函數:獲取當前插入的javascript,在IE6-9瀏覽器中,script的onload事件有時候並不能在script加載後觸發,須要遍歷script的節點才能知道,當前腳本狀態爲 'interactive'  node

 

config.jsjquery

/** * config.js - The configuration for the loader */

var BASE_RE = /^(.+?\/)(\?\?)?(seajs\/)+/

// The root path to use for id2uri parsing // If loaderUri is `http://test.com/libs/seajs/[??][seajs/1.2.3/]sea.js`, the // baseUri should be `http://test.com/libs/`
data.base = (loaderDir.match(BASE_RE) || ["", loaderDir])[1] // The loader directory
data.dir = loaderDir // The current working directory
data.cwd = cwd // The charset for requesting files
data.charset = "utf-8"

// Modules that are needed to load before all other modules
data.preload = (function() { var plugins = [] // Convert `seajs-xxx` to `seajs-xxx=1`
  // NOTE: use `seajs-xxx=1` flag in uri or cookie to preload `seajs-xxx`
  var str = location.search.replace(/(seajs-\w+)(&|$)/g, "$1=1$2") // Add cookie string
  str += " " + doc.cookie // Exclude seajs-xxx=0
  str.replace(/(seajs-\w+)=1/g, function(m, name) { plugins.push(name) }) return plugins })() // data.alias - An object containing shorthands of module id // data.paths - An object containing path shorthands in module id // data.vars - The {xxx} variables in module id // data.map - An array containing rules to map module uri // data.debug - Debug mode. The default value is false
 seajs.config = function(configData) { for (var key in configData) { var curr = configData[key] var prev = data[key] // Merge object config such as alias, vars
    if (prev && isObject(prev)) { for (var k in curr) { prev[k] = curr[k] } } else { // Concat array config such as map, preload
      if (isArray(prev)) { curr = prev.concat(curr) } // Make sure that `data.base` is an absolute path
      else if (key === "base") { // Make sure end with "/"
        if (curr.slice(-1) !== "/") { curr += "/" } curr = addBase(curr) } // Set config
      data[key] = curr } } emit("config", configData) return seajs }

 config.js的主要功能就是設置一些基本配置,包括base路徑,當前路徑,預加載模塊列表等,最主要的功能仍是config方法,把用戶傳入的自定義配置設置到seajs中去。web

相關文章
相關標籤/搜索