摘要:這里的依賴都是通過來異步加載的,加載完畢之后立刻執行函數,在模塊文件執行完畢后包括和其他代碼,觸發的事件。
入口 seajs.use
seajs.use直接調用Module.use(),Module.use的源碼如下:
// Use function is equal to load a anonymous module // ids:模塊標識,uri是dirname + "_use_0" + 數字自增變量 Module.use = function (ids, callback, uri) { // 從緩存cachedMods中獲取已存在的模塊對象或者新建module對象,并將緩存寫入其中,返回當前模塊對象 var mod = Module.get(uri, isArray(ids) ? ids : [ids]) // 對使用seajs.use或者require.async的模塊掛在一個callback。seajs.use的callback在所有依賴都loaded完畢之后才執行,通過require遞歸的exec()各個已經loaded的依賴模塊。這個callback作為seajs的入口,是所有模塊的factory開始執行的線頭起點。 mod.callback = function() { var exports = [] // resolve通過正則表達式解析當前模塊的依賴deps,并返回解析后的完成路徑,其值為一個數組 var uris = mod.resolve() // seajs.use入口處的依賴模塊依次開始執行,此為模塊執行的起點 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() } // Get an existed module or create a new one Module.get = function(uri, deps) { return cachedMods[uri] || (cachedMods[uri] = new Module(uri, deps)) } // Module構造函數 function Module(uri, deps) { this.uri = uri this.dependencies = deps || [] this.exports = null this.status = 0 // Who depends on me this._waitings = {} // 依賴當前模塊的對象 // The number of unloaded dependencies this._remain = 0 // 依賴的未加載完畢的模塊個數 }
load:加載當前模塊的依賴,并且在當前模塊的所有依賴都加載完畢后,觸發onload函數
// Load module.dependencies and fire onload when all done Module.prototype.load = function() { var mod = this // If the module is being loaded, just wait it onload call // 如果當前模塊正在被加載或者已經加載完畢,直接返回 if (mod.status >= STATUS.LOADING) { return } // 設置當前模塊為加載狀態 mod.status = STATUS.LOADING // Emit `load` event for plugins such as combo plugin // 解析當前加載模塊所有依賴文件的完整路徑 var uris = mod.resolve() emit("load", uris, mod) // 初始化模塊所依賴的未加載完畢的模塊的個數 var len = mod._remain = uris.length var m // Initialize modules and register waitings // 依次初始化當前mod依賴的deps為module對象,并且初始化_waitings,并存入cacheMods for (var i = 0; i < len; i++) { m = Module.get(uris[i]) if (m.status < STATUS.LOADED) { // Maybe duplicate: When module has dupliate dependency, it should be it"s count, not 1 // 如果當前依賴為未加載完成狀態,則該模塊的waiting + 1 m._waitings[mod.uri] = (m._waitings[mod.uri] || 0) + 1 } else { // 當前依賴已經加載完成,則模塊的remain - 1 mod._remain-- } } // 當前模塊的所有依賴都已經加載完畢時,觸發onload if (mod._remain === 0) { mod.onload() return } // Begin parallel loading var requestCache = {} // 通過fetch函數,加載當前mod依賴的所有模塊 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() } } // Send all requests at last to avoid cache bug in IE6-9. Issues#808 for (var requestUri in requestCache) { if (requestCache.hasOwnProperty(requestUri)) { requestCache[requestUri]() } } } // Call this method when module is loaded // 模塊的所有依賴都加載完畢后,執行onload Module.prototype.onload = function() { var mod = this mod.status = STATUS.LOADED // 對于使用require.async定義的模塊,有callback函數,在所有依賴模塊加載完畢后執行callback函數 if (mod.callback) { mod.callback() } // Notify waiting modules to fire onload // 當前模塊的所有依賴都加載完畢后,通知依賴當前模塊的所有模塊 var waitings = mod._waitings; var uri, m; for (uri in waitings) { if (waitings.hasOwnProperty(uri)) { m = cachedMods[uri] m._remain -= waitings[uri] if (m._remain === 0) { // 遞歸調用依賴當前模塊的模塊,執行onload函數,直到module.use頂端 m.onload() } } } // Reduce memory taken delete mod._waitings delete mod._remain }
fetch: fetch主要是通過創建標簽并且append到head來實現依賴的加載。這里的依賴都是通過async來異步加載的,加載完畢之后立刻執行define函數,在模塊文件執行完畢后(包括define和其他js代碼),觸發script的onload事件。
// Fetch a module Module.prototype.fetch = function(requestCache) { var mod = this var uri = mod.uri mod.status = STATUS.FETCHING // Emit `fetch` event for plugins such as combo plugin var emitData = { uri: uri } emit("fetch", emitData) var requestUri = emitData.requestUri || uri // Empty uri or a non-CMD module if (!requestUri || fetchedList[requestUri]) { mod.load() return } // fetchingList和callbackList為兩個全局對象,分別存放正在加載的模塊列表????? if (fetchingList[requestUri]) { callbackList[requestUri].push(mod) return } fetchingList[requestUri] = true callbackList[requestUri] = [mod] // Emit `request` event for plugins such as text plugin 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) } // script標簽的onload事件發生后,觸發onRequest方法 function onRequest() { delete fetchingList[requestUri] fetchedList[requestUri] = true // Save meta data of anonymous module if (anonymousMeta) { Module.save(uri, anonymousMeta) anonymousMeta = null } // Call callbacks var m, mods = callbackList[requestUri] delete callbackList[requestUri] while ((m = mods.shift())) m.load() } }
request: 將script添加到head,并且定義onload事件
seajs.request = function (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() } }
Module.define
// Define a module Module.define = function(id, deps, factory) { var argsLen = arguments.length // define(factory) if (argsLen === 1) { factory = id id = undefined } else if (argsLen === 2) { factory = deps // define(deps, factory) if (isArray(id)) { deps = id id = undefined1 `1` // define(id, factory) `` } else { deps = undefined } } // Parse dependencies according to the module factory code if (!isArray(deps) && isFunction(factory)) { deps = parseDependencies(factory.toString()) } var meta = { id: id, uri: Module.resolve(id), deps: deps, factory: factory } // Try to derive uri in IE6-9 for anonymous modules if (!meta.uri && doc.attachEvent) { var script = getCurrentScript() if (script) { meta.uri = script.src } // NOTE: If the id-deriving methods above is failed, then falls back // to use onload event to get the uri } // Emit `define` event, used in nocache plugin, seajs node version etc emit("define", meta) // Save information for "saving" work in the script onload event meta.uri ? Module.save(meta.uri, meta) : anonymousMeta = meta }
resolve
// Resolve module.dependencies Module.prototype.resolve = function() { var mod = this var ids = mod.dependencies var uris = [] for (var i = 0, len = ids.length; i < len; i++) { uris[i] = Module.resolve(ids[i], mod.uri) } return uris } // Resolve id to uri Module.resolve = function(id, refUri) { // Emit `resolve` event for plugins such as text plugin var emitData = { id: id, refUri: refUri } emit("resolve", emitData) return emitData.uri || seajs.resolve(emitData.id, refUri) } 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 } seajs.resolve = id2Uri;
https://seajs.github.io/seajs...
https://github.com/seajs/exam...
https://github.com/seajs/seajs
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99020.html
摘要:本文主要簡單地解讀一下的源碼和模塊化原理。其中,是這次源碼解讀的核心,但我也會順帶介紹一下其他文件的作用的。對代碼比較簡單,其實就是聲明一下全局的命名空間。然而,真正的核心在于處理模塊依賴的問題。 seajs 簡單介紹 seajs是前端應用模塊化開發的一種很好的解決方案。對于多人協作開發的、復雜龐大的前端項目尤其有用。簡單的介紹不多說,大家可以到seajs的官網seajs.org參看...
摘要:如果這個模塊的時候沒有設置,就表示是個匿名模塊,那怎么才能與之前發起請求的那個相匹配呢這里就有了一個全局變量,先將元數據放入這個對象。模塊加載完畢的回調保存元數據到匿名模塊,為請求的不管是不是匿名模塊,最后都是通過方法,將元數據存入到中。 近幾年前端工程化越來越完善,打包工具也已經是前端標配了,像seajs這種老古董早已停止維護,而且使用的人估計也幾個了。但這并不能阻止好奇的我,為了了...
摘要:所有依賴這個模塊的語句,都定義在一個回調函數中,等到所有依賴加載完成之后前置依賴,這個回調函數才會運行。如果將前面的代碼改寫成形式,就是下面這樣定義了一個文件,該文件依賴模塊,當模塊加載完畢之后執行回調函數,這里并沒有暴露任何變量。 模塊化是我們日常開發都要用到的基本技能,使用簡單且方便,但是很少人能說出來但是的原因及發展過程。現在通過對比不同時期的js的發展,將JavaScript模...
摘要:本文源碼為版本。的代碼結構也是一個很經典的定義結構構造函數實例修改函數原型共享實例方法,它提供事件通道上事件的訂閱撤消訂閱調用。 前言 cordova(PhoneGap) 是一個優秀的經典的中間件框架,網上對其源代碼解讀的文章確實不多,本系列文章試著解讀一下,以便對cordova 框架的原理理解得更深入。本文源碼為cordova android版本6.1.2。 源碼結構 我們使用IDE...
閱讀 769·2021-11-23 09:51
閱讀 835·2021-11-23 09:51
閱讀 2503·2021-11-15 18:01
閱讀 3863·2021-10-11 11:07
閱讀 2397·2021-09-22 15:30
閱讀 1075·2021-09-22 14:59
閱讀 1557·2019-08-30 15:55
閱讀 1753·2019-08-30 15:52