åè¨ï¼åä¸ç« 对Seajsçåºç¡åºç¨ï¼æ ¸å¿æ¨¡å以åè·¯å¾è§£æåè½é½åäºä»ç»ï¼è¿ä¸ç« å对Seajså©ä¸çå 项åè½åä¸ä¸ªç»¼åçä»ç»ã主è¦å æ¬Seajsäºä»¶æºå¶ï¼èæ¬å 载以å模åä¾èµã
代ç 解æï¼
ä¸ãSeajsäºä»¶æºå¶ï¼
Seajså é¨æä¾äºä»¥ä¸å ç§äºä»¶ç±»å:
seajs.on seajs.on(event, callback)
ç¨æ¥æ·»å äºä»¶åè°ã
// ç» fetch äºä»¶æ·»å ä¸ä¸ªåè°
seajs.on('fetch', function(data) {
...
});
seajs.off seajs.off(event?, callback?)
ç¨æ¥ç§»é¤äºä»¶åè°ã
// ä» fetch äºä»¶çåè°ä¸ç§»é¤æ fn å½æ°
seajs.off('fetch', fn);
// 移é¤æ fetch äºä»¶çææåè°
seajs.off('fetch');
// 移é¤æææäºä»¶çææåè°
seajs.off();
seajs.emit seajs.emit(event, data)
ç¨æ¥è§¦åäºä»¶ã
// 触å fetch äºä»¶
seajs.emit('fetch', { uri: uri, fetchedList: fetchedList });
以ä¸å°±æ¯Seajsäºä»¶æºå¶çæºç ï¼æ³¨éåå详ç»ï¼è¿éå°±ä¸å¤åä»ç»äºã
/**
* 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 - ; i >= ; i--) {
if (list[i] === callback) {
list.splice(i, )
}
}
}
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
//触åäºä»¶
//äºä»¶çåè°å½æ°é¾ä¿åå¨seajs.data.eventsä¸ï¼
//以äºä»¶å称为keyï¼Array对象ä¿åçåè°å½æ°é¾ä¸ºvalue
var emit = seajs.emit = function(name, data) {
var list = events[name]
if (list) {
// Copy callback lists to prevent modification
list = list.slice()
// Execute event callbacks, use index because it's the faster.
for(var i = , len = list.length; i < len; i++) {
list[i](data)
}
}
return seajs
}
äºãSeajsèæ¬å è½½
seajs.request()æ¹æ³ç¨äºä»æå¡ç«¯è¯·æ±å¯¹åºç模åã
//ä»æå¡ç«¯è¯·æ±æ¨¡å
function sendRequest() {
seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset, emitData.crossorigin)
}
æºç å¦ä¸ï¼å½æµè§å¨æ¯æwebworkeræ¶ï¼ç´æ¥è°ç¨importScriptå è½½å½æ°èæ¬ï¼å¦åçè¯ï¼éè¿å¨æå建scriptæ ç¾çæ¹å¼è¿è¡èæ¬å è½½ã为äºé²æ¢å¨IEä¸çå åæ³æ¼ï¼å¨èæ¬å è½½å®onloadä¹åï¼è¦åæ¶ç§»é¤è¯¥èæ¬ã
/**
* util-request.js - The utilities for requesting script and style files
* ref: tests/research/load-js-css/test.html
*/
//使ç¨webworkerå è½½jsèæ¬
if (isWebWorker) {
function requestFromWebWorker(url, callback, charset, crossorigin) {
// Load with importScripts
var error
try {
importScripts(url)
} catch (e) {
error = e
}
callback(error)
}
// For Developers
seajs.request = requestFromWebWorker
}
//å建scriptæ ç¾çæ¹å¼å è½½jsèæ¬
else {
var doc = document
var head = doc.head || doc.getElementsByTagName("head")[] || doc.documentElement
var baseElement = head.getElementsByTagName("base")[]
var currentlyAddingScript
function request(url, callback, charset, crossorigin) {
var node = doc.createElement("script")
if (charset) {
node.charset = charset
}
if (!isUndefined(crossorigin)) {
node.setAttribute("crossorigin", crossorigin)
}
addOnload(node, callback, url)
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, url) {
var supportOnload = "onload" in node
if (supportOnload) {
node.onload = onload
node.onerror = function() {
emit("error", { uri: url, node: node })
onload(true)
}
}
else {
node.onreadystatechange = function() {
if (/loaded|complete/.test(node.readyState)) {
onload()
}
}
}
function onload(error) {
// Ensure only run once and handle memory leak in IE
//为äºé²æ¢å¨IEä¸çå
åæ³æ¼ï¼å¨èæ¬å è½½å®onloadä¹åï¼ä¼åæ¶ç§»é¤è¯¥èæ¬
node.onload = node.onerror = node.onreadystatechange = null
// Remove the script to reduce memory leak
if (!data.debug) {
head.removeChild(node)
}
// Dereference the node
node = null
callback(error)
}
}
// For Developers
seajs.request = request
}
ä¸ãSeajs模åä¾èµ
Seajsç模åä¾èµéè¿æ¹æ³
parseDependencies
å®ç°ï¼å¤§ä½ä»£ç é»è¾æ¯éè¿ä½¿ç¨æ£åå¹é
require
çæ¹å¼å¾å°ä¾èµä¿¡æ¯ã
æ¶åå°çæ£å表达å¼å¦ä¸æ示ï¼
-
ï¼å¹é ææåæ¯ï¼ä¸åºå大å°åï¼/[a-z_$]/i
-
ï¼å¹é ææåæ¯ï¼æ°åï¼ä¸åºå大å°å;/^[\w$]+/
-
ï¼æµè¯æ¯å¦å«ærequire(âxxâ);/^require\s*\(\s*(['"]).+?\1\s*\)/
-
ï¼å¹é requireå ³é®åï¼/^require\s*\(\s*['"]/
-
ï¼å¹é 第ä¸ä¸ªåè¯ï¼/^[\w$]+(?:\s*\.\s*[\w$]+)*/
-
:è·å.ä¹åçæ´æ°æè æ¯.ä¹åç以ç§å¦è®¡æ°æ³è¡¨è¾¾çæ°å;/^\.\d+(?:E[+-]?\d*)?\s*/i
-
ï¼å¹é 以0xå¼å¤´[æ°å a-f]çå符串ï¼/^0x[\da-f]*/i
-
ï¼å¹é å°æ°æè 以ç§å¦è®¡æ°æ³è¡¨ç¤ºçå°æ°/^\d+\.?\d*(?:E[+-]?\d*)?\s*/i
æºç å¦ä¸æ示ï¼
/**
* util-deps.js - The parser for dependencies
* ref: tests/research/parse-dependencies/test.html
* ref: https://github.com/seajs/searequire
*/
//éè¿æ£åå¹é
requireçæ¹å¼å¾å°ä¾èµä¿¡æ¯
function parseDependencies(s) {
if(s.indexOf('require') == -) {
return []
}
var index = , peek, length = s.length, isReg = , modName = , parentheseState = , parentheseStack = [], res = []
while(index < length) {
readch()
if(isBlank()) {
}
else if(isQuote()) {
dealQuote()
isReg =
}
else if(peek == '/') {
readch()
if(peek == '/') {
index = s.indexOf('\n', index)
if(index == -) {
index = s.length
}
}
else if(peek == '*') {
index = s.indexOf('*/', index)
if(index == -) {
index = length
}
else {
index +=
}
}
else if(isReg) {
dealReg()
isReg =
}
else {
index--
isReg =
}
}
else if(isWord()) {
dealWord()
}
else if(isNumber()) {
dealNumber()
}
else if(peek == '(') {
parentheseStack.push(parentheseState)
isReg =
}
else if(peek == ')') {
isReg = parentheseStack.pop()
}
else {
isReg = peek != ']'
modName =
}
}
return res
function readch() {
//è¿åæå®ä½ç½®çå符
peek = s.charAt(index++)
}
function isBlank() {
return /\s/.test(peek)
}
function isQuote() {
return peek == '"' || peek == "'"
}
//ååº""æè
''ä¹é´çå符ï¼å³ä¾èµæ¨¡åçå称
function dealQuote() {
var start = index
var c = peek
var end = s.indexOf(c, start)
if(end == -) {
index = length
}
else if(s.charAt(end - ) != '\\') {
index = end +
}
else {
while(index < length) {
readch()
if(peek == '\\') {
index++
}
else if(peek == c) {
break
}
}
}
if(modName) {
res.push(s.slice(start, index - ))
modName =
}
}
function dealReg() {
index--
while(index < length) {
readch()
if(peek == '\\') {
index++
}
else if(peek == '/') {
break
}
else if(peek == '[') {
while(index < length) {
readch()
if(peek == '\\') {
index++
}
else if(peek == ']') {
break
}
}
}
}
}
function isWord() {
return /[a-z_$]/i.test(peek)
}
function dealWord() {
var s2 = s.slice(index - )
//å¹é
ææça-z,A-Z,0-9 @by sxy
var r = /^[\w$]+/.exec(s2)[]
parentheseState = {
'if': ,
'for': ,
'while': ,
'with':
}[r]
isReg = {
'break': ,
'case': ,
'continue': ,
'debugger': ,
'delete': ,
'do': ,
'else': ,
'false': ,
'if': ,
'in': ,
'instanceof': ,
'return': ,
'typeof': ,
'void':
}[r]
//æµè¯æ¯å¦å«ærequire("xx");
modName = /^require\s*\(\s*(['"]).+?\1\s*\)/.test(s2)
if(modName) {
//å¹é
requireå
³é®å
r = /^require\s*\(\s*['"]/.exec(s2)[]
index += r.length -
}
else {
//å¹é
第ä¸ä¸ªåè¯
index += /^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(s2)[].length -
}
}
function isNumber() {
return /\d/.test(peek)
|| peek == '.' && /\d/.test(s.charAt(index))
}
function dealNumber() {
var s2 = s.slice(index - )
var r
if(peek == '.') {
//TODO: è·å.ä¹åçæ´æ°æè
æ¯.ä¹åç以ç§å¦è®¡æ°æ³è¡¨è¾¾çæ°å
// /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(".671+22+s2ss21")[0] ==>.671
r = /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(s2)[]
}
//å¹é
以0xå¼å¤´[æ°å a-f]çå符串
else if(/^0x[\da-f]*/i.test(s2)) {
r = /^0x[\da-f]*\s*/i.exec(s2)[]
}
else {
//å¹é
å°æ°æè
以ç§å¦è®¡æ°æ³è¡¨ç¤ºçå°æ°
r = /^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(s2)[]
}
index += r.length -
isReg =
}
}
åãåè®°
è¿ä¸ç« ç±äºæ¶åå°çå 容æ¯è¾å¤ï¼ç¸åºçä»ç»çä¹æ¯è¾æ½¦èï¼å ¶å®Seajsçæ ¸å¿ä»£ç é½å·²ç»å¨åé¢å ç« ä»ç»å®æ¯äºï¼æ¬ç« çéçæåçæ¯å ¶ä¸çæ¹æ³å®ç°ãè³æ¤ï¼Seajsæºç åæç³»åå°æ¤ä¹è¦åä¸æ®µè½äºï¼ç±äºæ¥è§¦Seajsæ¶é´å¹¶ä¸é¿ï¼å¯¹å ¶äºè§£å¹¶æ²¡æå¤ªæ·±å ¥ï¼ä»¥ä¸å¾å¤è§è§£é½åªæ¯å窥é¨å¾ç½¢äºã