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

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

 更新時(shí)間:2016年10月21日 09:23:13   作者:royalrover  
做前端項(xiàng)目已經(jīng)離不開SeaJS了,現(xiàn)在的很多的網(wǎng)站都用了SeaJS,對(duì)這個(gè)JS模塊加載器原理的越來越感興趣。這篇文章我們來一起學(xué)習(xí)seajs模塊之間依賴的加載以及模塊的執(zhí)行,感興趣的朋友們下面來一起看看吧。

本文介紹的是seajs模塊之間依賴的加載以及模塊的執(zhí)行,下面話不多說直接來看詳細(xì)的介紹。

入口方法

每個(gè)程序都有個(gè)入口方法,類似于c的main函數(shù),seajs也不例外。系列一的demo在首頁使用了seajs.use() ,這便是入口方法。入口方法可以接受2個(gè)參數(shù),第一個(gè)參數(shù)為模塊名稱,第二個(gè)為回調(diào)函數(shù)。入口方法定義了一個(gè)新的模塊,這個(gè)新定義的模塊依賴入?yún)⑻峁┑哪K。然后設(shè)置新模塊的回調(diào)函數(shù),用以在loaded狀態(tài)之后調(diào)用。該回調(diào)函數(shù)主要是執(zhí)行所有依賴模塊的工廠函數(shù),最后在執(zhí)行入口方法提供的回調(diào)。

// Public API
// 入口地址
seajs.use = function(ids, callback) {
 Module.preload(function() {
 Module.use(ids, callback, data.cwd + "_use_" + cid())
 })
 return seajs
}

// Load preload modules before all other modules
Module.preload = function(callback) {
 var preloadMods = data.preload
 var len = preloadMods.length

 if (len) {
 Module.use(preloadMods, function() {
  // Remove the loaded preload modules
  preloadMods.splice(0, len)

  // Allow preload modules to add new preload modules
  Module.preload(callback)
 }, data.cwd + "_preload_" + cid())
 }
 else {
 callback()
 }
}

// Use function is equal to load a anonymous module
Module.use = function (ids, callback, uri) {
 var mod = Module.get(uri, isArray(ids) ? ids : [ids])

 mod.callback = function() {
 var exports = []
 var uris = mod.resolve()

 for (var i = 0, len = uris.length; i < len; i++) {
  exports[i] = cachedMods[uris[i]].exec()
 }
 // 回調(diào)函數(shù)的入?yún)?duì)應(yīng)依賴模塊的返回值
 if (callback) {
  callback.apply(global, exports)
 }

 delete mod.callback
 }

 mod.load()
}

Module.preload用于預(yù)加載seajs提供的插件plugins,非主要功能,可以忽略。而Module.use則是核心方法,該方法正如之前所說,創(chuàng)建新的module并設(shè)置回調(diào)函數(shù),最后加載新模塊的所有依賴模塊。

加載依賴之load方法

load方法可謂是seajs的精華所在。該方法主要加載依賴模塊并依次執(zhí)行依賴模塊的回調(diào)函數(shù),最終執(zhí)行的回調(diào)函數(shù)則是通過seajs.use(“./name”)創(chuàng)建的新模塊的回調(diào),也就是mod.callback 。

load方法遞歸加載依賴模塊,如果依賴模塊還依賴其他模塊,則再加載這個(gè)模塊。這是通過Module類中的_waitings_remain來實(shí)現(xiàn)的。

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
 for (var i = 0; i < len; i++) {
 m = Module.get(uris[i])

 // 修改 依賴文件 的 _waiting屬性
 if (m.status < STATUS.LOADED) {
  // Maybe duplicate: When module has dupliate dependency, it should be it's count, not 1
  m._waitings[mod.uri] = (m._waitings[mod.uri] || 0) + 1
 }
 else {
  mod._remain--
 }
 }

 // 加載完依賴,執(zhí)行模塊
 if (mod._remain === 0) {
 mod.onload()
 return
 }

 // Begin parallel loading
 var requestCache = {}

 for (i = 0; i < len; i++) {
 m = cachedMods[uris[i]]

 // 該依賴并未加載,則先fetch,將seajs.request函數(shù)綁定在對(duì)應(yīng)的requestCache上,此時(shí)并未加載模塊
 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)) {
  // 此時(shí)加載模塊
  requestCache[requestUri]()
 }
 }
}

// 依賴模塊加載完畢執(zhí)行回調(diào)函數(shù)
// 并檢查依賴該模塊的其他模塊是否可以執(zhí)行
Module.prototype.onload = function() {
 var mod = this
 mod.status = STATUS.LOADED

 if (mod.callback) {
 mod.callback()
 }
 console.log(mod)
 // 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) {
  m.onload()
  }
 }
 }

 // Reduce memory taken
 delete mod._waitings
 delete mod._remain
}

首先初始化模塊的_waitings_remain屬性,如果_remain為0,則意味著沒有依賴或者依賴已加載,可以執(zhí)行onload函數(shù);如果不為0,則fetch未加載的模塊。在這里有個(gè)實(shí)現(xiàn)的小技巧,就是同時(shí)加載所有依賴:requestCache對(duì)象保存加載函數(shù):(在fetch函數(shù)中定義)

if (!emitData.requested) {
 requestCache ?
  requestCache[emitData.requestUri] = sendRequest :
  sendRequest()
 }

其中,sendRequest函數(shù)定義如下:

function sendRequest() {
 seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)
 }

并行加載所有依賴,當(dāng)依賴加載完畢,執(zhí)行onRequest回調(diào),向上冒泡,加載依賴的依賴,直至沒有依賴模塊。

當(dāng)最上層的依賴已沒有依賴模塊時(shí),執(zhí)行onload函數(shù),在函數(shù)體內(nèi)設(shè)置狀態(tài)為loaded,執(zhí)行mod.callback,并檢查并設(shè)置該模塊的_waitings屬性,判斷下層模塊是否還有依賴,若沒有則執(zhí)行下層模塊的mod.callback,這一依次回溯,最終將會(huì)執(zhí)行通過seajs.use創(chuàng)建的匿名模塊的mod.callback。

例證

通過一個(gè)簡(jiǎn)單的例子,論證上述過程:

tst.html

<script>
  seajs.use('./b');
</script>
-------------------------------------
a.js

define(function(require,exports,module){
 exports.add = function(a,b){
  return a+b;
 }
})
------------------------------------
b.js

define(function(require,exports,module){
 var a = require("./a");
 console.log(a.add(3,5));
})

通過調(diào)試工具,可以看出執(zhí)行onload的次序:

最后可看出,匿名模塊的狀態(tài)碼為4,也就是該模塊并未執(zhí)行.確實(shí),也沒有給匿名模塊定義工廠函數(shù),無法執(zhí)行.

模塊執(zhí)行之exec

模塊執(zhí)行是在seajs.use中定義的mod.callback中調(diào)用的,依次調(diào)用所有依賴的exec方法,執(zhí)行程序邏輯。exec方法中有commonJS的一些重要關(guān)鍵字或者函數(shù),如requireexports等,讓我們一看究竟:

Module.prototype.exec = function () {
 var mod = this

 // When module is executed, DO NOT execute it again. When module
 // is being executed, just return `module.exports` too, for avoiding
 // circularly calling
 if (mod.status >= STATUS.EXECUTING) {
 return mod.exports
 }

 mod.status = STATUS.EXECUTING

 // Create require
 var uri = mod.uri

 function require(id) {
 return Module.get(require.resolve(id)).exec()
 }

 require.resolve = function(id) {
 return Module.resolve(id, uri)
 }

 require.async = function(ids, callback) {
 Module.use(ids, callback, uri + "_async_" + cid())
 return require
 }

 // Exec factory
 var factory = mod.factory

 // 工廠函數(shù)有返回值,則返回;
 // 無返回值,則返回mod.exports
 var exports = isFunction(factory) ?
  factory(require, mod.exports = {}, mod) :
  factory

 if (exports === undefined) {
 exports = mod.exports
 }

 // Reduce memory leak
 delete mod.factory

 mod.exports = exports
 mod.status = STATUS.EXECUTED

 // Emit `exec` event
 emit("exec", mod)

 return exports
}

require函數(shù)獲取模塊并執(zhí)行模塊的工廠函數(shù),獲取返回值。require函數(shù)的resolve方法則是獲取對(duì)應(yīng)模塊名的絕對(duì)url,require函數(shù)的async方法異步加載依賴并執(zhí)行回調(diào)。對(duì)于工廠方法的返回值,如果工廠方法為對(duì)象,則這就是exports的值;or工廠方法有返回值,則為exports的值;or module.exports的值為exports的值。當(dāng)可以獲取到exports值時(shí),設(shè)置狀態(tài)為executed。

值得注意的一點(diǎn):當(dāng)想要通過給exports賦值來導(dǎo)出一個(gè)對(duì)象時(shí)

define(function(require,exports,module){
 exports ={
  add: function(a,b){
    return a+b;
  }
 }
})

是不成功的.我們通過執(zhí)行上述方法來判斷最終導(dǎo)出exports的值.首先,函數(shù)沒有返回值,其次,mod.exports為undefined,最終導(dǎo)出的exportsundefined。為什么會(huì)出現(xiàn)這種情況呢?是因?yàn)閖s中引用賦值所造成的。js的賦值策略是“按共享傳遞”,雖說初始時(shí)exports === module.exports,但是當(dāng)給exports賦一個(gè)對(duì)象時(shí),此時(shí)exports指向該對(duì)象,module.exports卻仍未初始化,為undefined,因此會(huì)出錯(cuò)。

正確的寫法為

define(function(require,exports,module){
 module.exports ={
  add: function(a,b){
    return a+b;
  }
 }
})

總結(jié)

可以說,seajs的核心模塊的實(shí)現(xiàn)已講解完畢,見識(shí)了不少編碼技巧,領(lǐng)略了回調(diào)模式的巧妙,以及于細(xì)微處的考量。代碼的每一處都考慮到了內(nèi)存泄露和this指針引用偏移的危險(xiǎn),做了積極的預(yù)防,這種精神值得學(xué)習(xí)。

對(duì)于seajs,前前后后花了不下一個(gè)星期來閱讀源碼,從剛開始的一知半解到如今的拜服,我真切的領(lǐng)會(huì)到了設(shè)計(jì)思想的重要性。之前我不怎么重視實(shí)現(xiàn)的技巧性,認(rèn)為能夠?qū)崿F(xiàn),不出bug,健壯性良好即可,但是現(xiàn)在我意識(shí)到錯(cuò)了,尤其是在load依賴模塊那部分實(shí)現(xiàn)中,技巧性十足。以上就是本文的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

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

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

    這篇文章主要介紹了seajs中最常用的7個(gè)功能、配置,結(jié)合實(shí)例形式簡(jiǎn)單分析了seajs中常用的項(xiàng)目配置、模塊加載、定義、獲取等操作技巧,需要的朋友可以參考下
    2017-10-10
  • Seajs 簡(jiǎn)易文檔 提供簡(jiǎn)單、極致的模塊化開發(fā)體驗(yàn)

    Seajs 簡(jiǎn)易文檔 提供簡(jiǎn)單、極致的模塊化開發(fā)體驗(yàn)

    這篇文章主要介紹了Seajs 簡(jiǎn)易文檔 提供簡(jiǎn)單、極致的模塊化開發(fā)體驗(yàn),非官方文檔,整理來自己官方文檔的文字與實(shí)例,方便速查。需要的朋友可以參考下
    2016-04-04
  • seajs下require書寫約定實(shí)例分析

    seajs下require書寫約定實(shí)例分析

    這篇文章主要介紹了seajs下require書寫約定,結(jié)合實(shí)例形式分析了seajs中require書寫約定遵循的規(guī)則,需要的朋友可以參考下
    2018-05-05
  • 詳解Sea.js中Module.exports和exports的區(qū)別

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

    最近在看Seajs時(shí),看到了exports.doSomething和module.exports,想對(duì)這兩者的區(qū)別一探究竟。所以下面這篇文章主要介紹了Sea.js中Module.exports和exports的區(qū)別,需要的朋友可以參考借鑒,一起來看看吧。
    2017-02-02
  • Seajs的學(xué)習(xí)筆記

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

    這篇文章主要介紹了Seajs的相關(guān)知識(shí)和和學(xué)習(xí)心得,適合剛接觸SeaJS的同學(xué),需要的朋友可以參考下
    2014-03-03
  • SeaJS中use函數(shù)用法實(shí)例分析

    SeaJS中use函數(shù)用法實(shí)例分析

    這篇文章主要介紹了SeaJS中use函數(shù)用法,結(jié)合實(shí)例形式分析了use函數(shù)加載模塊的使用方法與相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • Seajs源碼詳解分析

    Seajs源碼詳解分析

    近幾年前端工程化越來越完善,打包工具也已經(jīng)是前端標(biāo)配了,像seajs這種老古董早已停止維護(hù),這是一篇細(xì)細(xì)品味Seajs源碼的文章,看完一定受益匪淺
    2019-04-04
  • seajs實(shí)現(xiàn)強(qiáng)制刷新本地緩存的方法分析

    seajs實(shí)現(xiàn)強(qiáng)制刷新本地緩存的方法分析

    這篇文章主要介紹了seajs實(shí)現(xiàn)強(qiáng)制刷新本地緩存的方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了seajs強(qiáng)制刷新本地緩存的原理、實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-10-10
  • seajs模塊之間依賴的加載以及模塊的執(zhí)行

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

    做前端項(xiàng)目已經(jīng)離不開SeaJS了,現(xiàn)在的很多的網(wǎng)站都用了SeaJS,對(duì)這個(gè)JS模塊加載器原理的越來越感興趣。這篇文章我們來一起學(xué)習(xí)seajs模塊之間依賴的加載以及模塊的執(zhí)行,感興趣的朋友們下面來一起看看吧。
    2016-10-10
  • seajs模塊壓縮問題與解決方法實(shí)例分析

    seajs模塊壓縮問題與解決方法實(shí)例分析

    這篇文章主要介紹了seajs模塊壓縮問題與解決方法,結(jié)合實(shí)例形式分析了seajs模塊壓縮過程中出現(xiàn)的問題及相應(yīng)的解決方法,需要的朋友可以參考下
    2017-10-10

最新評(píng)論