欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

seajs學(xué)習(xí)之模塊的依賴加載及模塊API的導(dǎo)出

 更新時(shí)間:2016年10月20日 15:35:01   作者:royalrover  
SeaJS是一個(gè)遵循 CommonJS 規(guī)范的模塊加載框架,可用來輕松愉悅地加載任意JavaScript模塊和css模塊樣式。SeaJS接口和方法也非常少,SeaJS 就兩個(gè)核心:模塊定義和模塊的加載及依賴關(guān)系。本文將詳細(xì)介紹模塊的依賴加載及模塊API的導(dǎo)出,有需要的朋友們可以參考借鑒。

前言

SeaJS非常強(qiáng)大,SeaJS可以加載任意 JavaScript 模塊和css模塊樣式,SeaJS會保證你在使用一個(gè)模塊時(shí),已經(jīng)將所依賴的其他模塊載入到腳本運(yùn)行環(huán)境中。

通過參照上文的demo,我們結(jié)合源碼分析在簡單的API調(diào)用的背后,到底使用了什么技巧來實(shí)現(xiàn)各個(gè)模塊的依賴加載以及模塊API的導(dǎo)出。

模塊類和狀態(tài)類

首先定義了一個(gè)Module類,對應(yīng)與一個(gè)模塊

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
}

Module有一些屬性,uri對應(yīng)該模塊的絕對url,在Module.define函數(shù)中會有介紹;dependencies為依賴模塊數(shù)組;exports為導(dǎo)出的API;status為當(dāng)前的狀態(tài)碼;_waitings對象為當(dāng)前依賴該模塊的其他模塊哈希表,其中key為其他模塊的url;_remain為計(jì)數(shù)器,記錄還未加載的模塊個(gè)數(shù)。

var STATUS = Module.STATUS = {
 // 1 - The `module.uri` is being fetched
 FETCHING: 1,
 // 2 - The meta data has been saved to cachedMods
 SAVED: 2,
 // 3 - The `module.dependencies` are being loaded
 LOADING: 3,
 // 4 - The module are ready to execute
 LOADED: 4,
 // 5 - The module is being executed
 EXECUTING: 5,
 // 6 - The `module.exports` is available
 EXECUTED: 6
}

上述為狀態(tài)對象,記錄模塊的當(dāng)前狀態(tài):模塊初始化狀態(tài)為0,當(dāng)加載該模塊時(shí),為狀態(tài)fetching;模塊加載完畢并且緩存在cacheMods后,為狀態(tài)saved;loading狀態(tài)意味著正在加載該模塊的其他依賴模塊;loaded表示所有依賴模塊加載完畢,執(zhí)行該模塊的回調(diào)函數(shù),并設(shè)置依賴該模塊的其他模塊是否還有依賴模塊未加載,若加載完畢執(zhí)行回調(diào)函數(shù);executing狀態(tài)表示該模塊正在執(zhí)行;executed則是執(zhí)行完畢,可以使用exports的API。

模塊的定義

commonJS規(guī)范規(guī)定用define函數(shù)來定義一個(gè)模塊。define可以接受1,2,3個(gè)參數(shù)均可,不過對于Module/wrappings規(guī)范而言,module.declare或者define函數(shù)只能接受一個(gè)參數(shù),即工廠函數(shù)或者對象。不過原則上接受參數(shù)的個(gè)數(shù)并沒有本質(zhì)上的區(qū)別,只不過庫在后臺給額外添加模塊名。

seajs鼓勵使用define(function(require,exports,module){})這種模塊定義方式,這是典型的Module/wrappings規(guī)范實(shí)現(xiàn)。但是在后臺通過解析工廠函數(shù)的require方法來獲取依賴模塊并給模塊設(shè)置id和url。

// 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 = undefined
 }
 // define(id, factory)
 else {
 deps = undefined
 }
 }

 // Parse dependencies according to the module factory code
 // 如果deps為非數(shù)組,則序列化工廠函數(shù)獲取入?yún)ⅰ?
 if (!isArray(deps) && isFunction(factory)) {
 deps = parseDependencies(factory.toString())
 }

 var meta = {
 id: id,
 uri: Module.resolve(id), // 絕對url
 deps: deps,
 factory: factory
 }

 // Try to derive uri in IE6-9 for anonymous modules
 // 導(dǎo)出匿名模塊的uri
 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)

 meta.uri ? Module.save(meta.uri, meta) :
 // Save information for "saving" work in the script onload event
 anonymousMeta = meta
}

模塊定義的最后,通過Module.save方法,將模塊保存到cachedMods緩存體中。

parseDependencies方法比較巧妙的獲取依賴模塊。他通過函數(shù)的字符串表示,使用正則來獲取require(“…”)中的模塊名。

var REQUIRE_RE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g
var SLASH_RE = /\\\\/g

function parseDependencies(code) {
 var ret = []
 // 此處使用函數(shù)序列化(傳入的factory)進(jìn)行字符串匹配,尋找require(“...”)的關(guān)鍵字
 code.replace(SLASH_RE, "")
 .replace(REQUIRE_RE, function(m, m1, m2) {
 if (m2) {
  ret.push(m2)
 }
 })

 return ret
}

異步加載模塊

加載模塊可以有多種方式,xhr方式可以同步加載,也可以異步加載,但是存在同源問題,因此難以在此使用。另外script tag方式在IE和現(xiàn)代瀏覽器下可以保證并行加載和順序執(zhí)行,script element方式也可以保證并行加載但不保證順序執(zhí)行,因此這兩種方式都可以使用。

在seajs中,是采用script element方式來并行加載js/css資源的,并針對舊版本的webkit瀏覽器加載css做了hack。

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
 }
 }

 // 添加 onload 函數(shù)。
 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()
 }
}
// 針對 舊webkit和不支持onload的CSS節(jié)點(diǎn)判斷加載完畢的方法
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)
}

其中有些細(xì)節(jié)還需注意,當(dāng)采用script element方法插入script節(jié)點(diǎn)時(shí),盡量作為首個(gè)子節(jié)點(diǎn)插入到head中,這是由于一個(gè)難以發(fā)現(xiàn)的bug:

GLOBALEVAL WORKS INCORRECTLY IN IE6 IF THE CURRENT PAGE HAS <BASE HREF> TAG IN THE HEAD

fetch模塊

初始化Module對象時(shí),狀態(tài)為0,該對象對應(yīng)的js文件并未加載,若要加載js文件,需要使用上節(jié)提到的request方法,但是也不可能僅僅加載該文件,還需要設(shè)置module對象的狀態(tài)及其加載module依賴的其他模塊。

這些邏輯在fetch方法中得以體現(xiàn):

// Fetch a module
// 加載該模塊,fetch函數(shù)中調(diào)用了seajs.request函數(shù)
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
 }

 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)
 }
 // 回調(diào)函數(shù)
 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()
 }
}

其中seajs.request就是上節(jié)的request方法。onRequest作為回調(diào)函數(shù),作用是加載該模塊的其他依賴模塊。

總結(jié)

以上就是seajs模塊的依賴加載及模塊API的導(dǎo)出的全部內(nèi)容了,小編會在下一節(jié),將介紹模塊之間依賴的加載以及模塊的執(zhí)行。感興趣的朋友們可以繼續(xù)關(guān)注腳本之家。

相關(guān)文章

  • SeaJS入門教程系列之完整示例(三)

    SeaJS入門教程系列之完整示例(三)

    這篇文章主要介紹了SeaJS入門教程系列之完整示例,演示了一個(gè)完整的SeaJS開發(fā)例子,需要的朋友可以參考下
    2014-03-03
  • seajs學(xué)習(xí)之模塊的依賴加載及模塊API的導(dǎo)出

    seajs學(xué)習(xí)之模塊的依賴加載及模塊API的導(dǎo)出

    SeaJS是一個(gè)遵循 CommonJS 規(guī)范的模塊加載框架,可用來輕松愉悅地加載任意JavaScript模塊和css模塊樣式。SeaJS接口和方法也非常少,SeaJS 就兩個(gè)核心:模塊定義和模塊的加載及依賴關(guān)系。本文將詳細(xì)介紹模塊的依賴加載及模塊API的導(dǎo)出,有需要的朋友們可以參考借鑒。
    2016-10-10
  • SeaJS入門教程系列之使用SeaJS(二)

    SeaJS入門教程系列之使用SeaJS(二)

    這篇文章主要介紹了SeaJS入門教程系列之使用SeaJS,著重介紹了SeaJS的使用方法、關(guān)鍵方法的使用等,需要的朋友可以參考下
    2014-03-03
  • seajs模塊之間依賴的加載以及模塊的執(zhí)行

    seajs模塊之間依賴的加載以及模塊的執(zhí)行

    做前端項(xiàng)目已經(jīng)離不開SeaJS了,現(xiàn)在的很多的網(wǎng)站都用了SeaJS,對這個(gè)JS模塊加載器原理的越來越感興趣。這篇文章我們來一起學(xué)習(xí)seajs模塊之間依賴的加載以及模塊的執(zhí)行,感興趣的朋友們下面來一起看看吧。
    2016-10-10
  • 詳解Sea.js中Module.exports和exports的區(qū)別

    詳解Sea.js中Module.exports和exports的區(qū)別

    最近在看Seajs時(shí),看到了exports.doSomething和module.exports,想對這兩者的區(qū)別一探究竟。所以下面這篇文章主要介紹了Sea.js中Module.exports和exports的區(qū)別,需要的朋友可以參考借鑒,一起來看看吧。
    2017-02-02
  • seajs中最常用的7個(gè)功能、配置示例

    seajs中最常用的7個(gè)功能、配置示例

    這篇文章主要介紹了seajs中最常用的7個(gè)功能、配置,結(jié)合實(shí)例形式簡單分析了seajs中常用的項(xiàng)目配置、模塊加載、定義、獲取等操作技巧,需要的朋友可以參考下
    2017-10-10
  • 深入探尋seajs的模塊化與加載方式

    深入探尋seajs的模塊化與加載方式

    本文是對Sea.js 提供seajs的模塊化與加載方式的講解,對學(xué)習(xí)JavaScript編程技術(shù)有所幫助,與大家分享。有需要的小伙伴可以參考下。
    2015-04-04
  • seaJs的模塊定義和模塊加載淺析

    seaJs的模塊定義和模塊加載淺析

    這篇文章主要介紹了seaJs的模塊定義和模塊加載淺析,以及模塊間的依賴關(guān)系等問題,需要的朋友可以參考下
    2014-06-06
  • Vue實(shí)現(xiàn)圖片懶加載的多種方法詳解

    Vue實(shí)現(xiàn)圖片懶加載的多種方法詳解

    圖片懶加載是前端開發(fā)中一項(xiàng)重要的性能優(yōu)化策略,它能夠明顯縮短頁面加載時(shí)間,提升用戶的瀏覽體驗(yàn),在本文中,我們將深入探討在Vue開發(fā)時(shí)候如何實(shí)現(xiàn)圖片懶加載,同時(shí)探討多種實(shí)現(xiàn)途徑,需要的朋友可以參考下
    2023-08-08
  • Seajs的學(xué)習(xí)筆記

    Seajs的學(xué)習(xí)筆記

    這篇文章主要介紹了Seajs的相關(guān)知識和和學(xué)習(xí)心得,適合剛接觸SeaJS的同學(xué),需要的朋友可以參考下
    2014-03-03

最新評論