Sea.js:css
var seajs = global.seajs = { // The current version of Sea.js being used version: "@VERSION" } var data = seajs.data = {}
代碼定義了一個seajs變量並暴露給全局,變量如今只有一個值就是版本號變量html
另外定義了一個data變量,後面會用到 node
util-lang.jsgit
/** * util-lang.js - The minimal language enhancement */ function isType(type) { return function(obj) { return {}.toString.call(obj) == "[object " + type + "]" } } var isObject = isType("Object") var isString = isType("String") var isArray = Array.isArray || isType("Array") var isFunction = isType("Function") var isUndefined = isType("Undefined") var _cid = 0 function cid() { return _cid++ }
這裏用一個函數來判斷對象類型,這裏有一個演變過程比較有意思,若是有興趣能夠參考下玉伯的github博客github
cid方法用來產生一個惟一的ID,後面會用到正則表達式
util-events.js數組
/** * util-events.js - The minimal events support */ var events = data.events = {} // Bind event seajs.on = function(name, callback) { var list = events[name] || (events[name] = []) list.push(callback) return seajs } // Remove event. If `callback` is undefined, remove all callbacks for the // event. If `event` and `callback` are both undefined, remove all callbacks // for all events seajs.off = function(name, callback) { // Remove *all* events if (!(name || callback)) { events = data.events = {} return seajs } var list = events[name] if (list) { if (callback) { for (var i = list.length - 1; i >= 0; i--) { if (list[i] === callback) { list.splice(i, 1) } } } else { delete events[name] } } return seajs } // Emit event, firing all bound callbacks. Callbacks receive the same // arguments as `emit` does, apart from the event name var emit = seajs.emit = function(name, data) { var list = events[name], fn if (list) { // Copy callback lists to prevent modification list = list.slice() // Execute event callbacks while ((fn = list.shift())) { fn(data) } } return seajs }
一個事件處理機制,on用來註冊事件,爲指定事件數組添加回調函數,off用來移除事件,若是沒有指定事件名和回調函數,刪除全部事件的回調函數,若是沒有指定回調函數,則刪除該事件的全部回調函數,emit用來觸發事件以及事件綁定的函數app
util-path.jsjsp
/** * util-path.js - The utilities for operating path such as id, uri */ var DIRNAME_RE = /[^?#]*\// var DOT_RE = /\/\.\//g var DOUBLE_DOT_RE = /\/[^/]+\/\.\.\// var DOUBLE_SLASH_RE = /([^:/])\/\//g // Extract the directory portion of a path // dirname("a/b/c.js?t=123#xx/zz") ==> "a/b/" // ref: http://jsperf.com/regex-vs-split/2 function dirname(path) { return path.match(DIRNAME_RE)[0] } // Canonicalize a path // realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c" function realpath(path) { // /a/b/./c/./d ==> /a/b/c/d path = path.replace(DOT_RE, "/") // a/b/c/../../d ==> a/b/../d ==> a/d while (path.match(DOUBLE_DOT_RE)) { path = path.replace(DOUBLE_DOT_RE, "/") } // a//b/c ==> a/b/c path = path.replace(DOUBLE_SLASH_RE, "$1/") return path } // Normalize an id // normalize("path/to/a") ==> "path/to/a.js" // NOTICE: substring is faster than negative slice and RegExp function normalize(path) { var last = path.length - 1 var lastC = path.charAt(last) // If the uri ends with `#`, just return it without '#' if (lastC === "#") { return path.substring(0, last) } return (path.substring(last - 2) === ".js" || path.indexOf("?") > 0 || path.substring(last - 3) === ".css" || lastC === "/") ? path : path + ".js" } var PATHS_RE = /^([^/:]+)(\/.+)$/ var VARS_RE = /{([^{]+)}/g function parseAlias(id) { var alias = data.alias return alias && isString(alias[id]) ? alias[id] : id } function parsePaths(id) { var paths = data.paths var m if (paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) { id = paths[m[1]] + m[2] } return id } function parseVars(id) { var vars = data.vars if (vars && id.indexOf("{") > -1) { id = id.replace(VARS_RE, function(m, key) { return isString(vars[key]) ? vars[key] : m }) } return id } function parseMap(uri) { var map = data.map var ret = uri if (map) { for (var i = 0, len = map.length; i < len; i++) { var rule = map[i] ret = isFunction(rule) ? (rule(uri) || uri) : uri.replace(rule[0], rule[1]) // Only apply the first matched rule if (ret !== uri) break } } return ret } var ABSOLUTE_RE = /^\/\/.|:\// var ROOT_DIR_RE = /^.*?\/\/.*?\// function addBase(id, refUri) { var ret var first = id.charAt(0) // Absolute if (ABSOLUTE_RE.test(id)) { ret = id } // Relative else if (first === ".") { ret = realpath((refUri ? dirname(refUri) : data.cwd) + id) } // Root else if (first === "/") { var m = data.cwd.match(ROOT_DIR_RE) ret = m ? m[0] + id.substring(1) : id } // Top-level else { ret = data.base + id } // Add default protocol when uri begins with "//" if (ret.indexOf("//") === 0) { ret = location.protocol + ret } return ret } function id2Uri(id, refUri) { if (!id) return "" id = parseAlias(id) id = parsePaths(id) id = parseVars(id) id = normalize(id) var uri = addBase(id, refUri) uri = parseMap(uri) return uri } var doc = document var cwd = dirname(doc.URL) var scripts = doc.scripts // Recommend to add `seajsnode` id for the `sea.js` script element var loaderScript = doc.getElementById("seajsnode") || scripts[scripts.length - 1] // When `sea.js` is inline, set loaderDir to current working directory var loaderDir = dirname(getScriptAbsoluteSrc(loaderScript) || cwd) function getScriptAbsoluteSrc(node) { return node.hasAttribute ? // non-IE6/7 node.src : // see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx node.getAttribute("src", 4) } // For Developers seajs.resolve = id2Uri
這段代碼是用來進行路徑處理的:函數
首先定義了一組正則表達式用來路徑分析
dirname函數:得到一組路徑的目錄部分,好比dirname("a/b/c.js?t=123#xx/zz") 得到的結果是a/b
realpath函數:規範一組路徑,好比realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c",就是將./ ../ 和//轉換成規範的路徑
normalize函數:規範一組路徑的後綴名,好比normalize("path/to/a") ==> "path/to/a.js".
parseAlias函數:路徑別名處理,根據別名id返回別名
parsePaths:解析配置中的path,具體能夠參考config用法
parseVars:解析配置中的變量
parseMap:解析配置中的map
addBase:將路徑轉換爲完整路徑
id2Uri:將模塊id轉換爲真實完整路徑
util-deps.js:
/** * util-deps.js - The parser for dependencies * ref: tests/research/parse-dependencies/test.html */ var REQUIRE_RE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g var SLASH_RE = /\\\\/g function parseDependencies(code) { var ret = [] code.replace(SLASH_RE, "") .replace(REQUIRE_RE, function(m, m1, m2) { if (m2) { ret.push(m2) } }) return ret }
解析模塊代碼中require的模塊,也就是依賴模塊解析