摘要:依賴信息是一個數(shù)組,比如上面的依賴數(shù)組是源碼如下是利用正則解析依賴的一個函數(shù)時間出發(fā)函數(shù)主要看這個部分注釋是防止拷貝該時間的回調(diào)函數(shù),防止修改,困惑了一下。對的賦值需要同步執(zhí)行,不能放在回調(diào)函數(shù)里。
sea.js想解決的問題
惱人的命名沖突
煩瑣的文件依賴
對應(yīng)帶來的好處 Sea.js 帶來的兩大好處:通過 exports 暴露接口。這意味著不需要命名空間了,更不需要全局變量。這是一種徹底的命名沖突解決方案。
通過 require 引入依賴。這可以讓依賴內(nèi)置,開發(fā)者只需關(guān)心當前模塊的依賴,其他事情 Sea.js 都會自動處理好。對模塊開發(fā)者來說,這是一種很好的 關(guān)注度分離,能讓程序員更多地享受編碼的樂趣。
API速查1. seajs.config 2. seajs.use 3. define 4. require 5. require.async 6. exports 7. module.exportssea.js的執(zhí)行過程 啟動
用script標簽引入sea.js文件,seajs.config(data)啟動配置函數(shù),config函數(shù)會會合并所有config配置,seajs.use = function(ids, callback),啟用主腳本
運行過程主腳本啟動之后,首先利用request模塊請求主腳本(生成script標簽插入head標簽中),然后根據(jù)正則解析模塊define的依賴,并對依賴遞歸解析其依賴。
在運行過程中,通過監(jiān)聽發(fā)布者模式,系統(tǒng)內(nèi)置了8個事件,可用于開發(fā)插件。
resolve -- 將 id 解析成為 uri 時觸發(fā) load -- 開始加載文件時觸發(fā) fetch -- 具體獲取某個 uri 時觸發(fā) request -- 發(fā)送請求時觸發(fā) define -- 執(zhí)行 define 方法時觸發(fā) exec -- 執(zhí)行 module.factory 時觸發(fā) config -- 調(diào)用 seajs.config 時觸發(fā) error -- 加載腳本文件出現(xiàn) 404 或其他錯誤時觸發(fā)全局掛載
所有相關(guān)數(shù)據(jù)最后全部掛載在window.seajs下,包括方法及模塊數(shù)據(jù)。
小知識點 exports與module.exportsexports 僅僅是 module.exports 的一個引用。在 factory 內(nèi)部給 exports 重新賦值時,并不會改變 module.exports 的值。因此給 exports 賦值是無效的,不能用來更改模塊接口。
//源碼如下 // Exec factory var factory = mod.factory; var exports = isFunction(factory) ? factory.call(mod.exports = {}, require, mod.exports, mod) : factory關(guān)于動態(tài)依賴
有時會希望可以使用 require 來進行條件加載:
if (todayIsWeekend) require("play"); else require("work");
但請牢記,從靜態(tài)分析的角度來看,這個模塊同時依賴 play 和 work 兩個模塊,加載器會把這兩個模塊文件都下載下來。 這種情況下,推薦使用 require.async 來進行條件加載。
//sea.js源碼如下 require.async = function(ids, callback) { //可傳入回調(diào)函數(shù) Module.use(ids, callback, uri + "_async_" + cid()) //——async_英語標識這個腳本是異步加載的,cid用于清除緩存 return require //返回require方便鏈式調(diào)用 }在開發(fā)時,Sea.js 是如何知道一個模塊的具體依賴呢?
a.js
define(function(require, exports) { var b = require("./b"); var c = require("./c"); });
Sea.js 在運行 define 時,接受 factory 參數(shù),可以通過 factory.toString() 拿到源碼,再通過正則匹配 require 的方式來得到依賴信息。依賴信息是一個數(shù)組,比如上面 a.js 的依賴數(shù)組是:["./b", "./c"]
//源碼如下 // Parse dependencies according to the module factory code if (!isArray(deps) && isFunction(factory)) { deps = typeof parseDependencies === "undefined" ? [] : parseDependencies(factory.toString()) //parseDependencies是利用正則解析依賴的一個函數(shù) }時間出發(fā)函數(shù)Emit
// 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] if (list) { // Copy callback lists to prevent modification list = list.slice() // Execute event callbacks, use index because it"s the faster. for(var i = 0, len = list.length; i < len; i++) { list[i](data) } } return seajs }
主要看這個部分list = list.slice(),注釋是防止拷貝該時間的回調(diào)函數(shù),防止修改,困惑了一下。
原因是Javascript中賦值時,對于引用數(shù)據(jù)類型,都是傳地址。
所以這里,如果想防止觸發(fā)事件的過程中回調(diào)函數(shù)被更改,必須對這個list數(shù)組進行拷貝,而并非只是將list指向events[name]的地址。
// Remove the script to reduce memory leak if (!data.debug) { head.removeChild(node) }
這里思考了蠻久,為什么可以刪除動態(tài)插入的腳本?這樣腳本還會生效嗎?
首先,必須了解計算機內(nèi)存分為
靜態(tài)數(shù)據(jù)區(qū) (用來存放程序中初始化的全局變量的一塊內(nèi)存區(qū)域)
代碼區(qū) (通常用來存放執(zhí)行代碼的一塊內(nèi)存區(qū)域)
棧區(qū) (棧在進程運行時產(chǎn)生,一個進程有一個進程棧。棧用來存儲程序臨時存放的局部變量,即函數(shù)內(nèi)定義的變量 不包括static 類型的。函數(shù)被調(diào)用時,他的形參也會被壓棧。
堆區(qū) (用于存放進程運行中被動態(tài)分配的內(nèi)存段,它的大小并且不固定,可動態(tài)擴展。當進程調(diào)用malloc等分配內(nèi)存時,新分配的內(nèi)存被動態(tài)的添加到堆上(堆被擴大),當利用free等函數(shù)釋放內(nèi)存時,被釋放的‘ 內(nèi)存從堆中剔除)
這些在Javascript中都被屏蔽了,大部分時候我們都不需要考慮,但是如果要深入了解的話,則是必須要知道的知識。
首先HTML文檔中的JS腳本在計算機中作為指令被讀入內(nèi)存,之后開始執(zhí)行,CPU開始一條一條指令讀取,比如,讀取到var cool = "wilson"時,就會在內(nèi)存中分配一個6字符大小的內(nèi)存,一個function也一樣會在內(nèi)存中占據(jù)一定大小。所以,當指令全部運行完之后,指令本身其實已經(jīng)沒有用了,但是仍然給占據(jù)了一部分內(nèi)存。
當你點擊按鈕觸發(fā)一個回調(diào)函數(shù)時,并非去讀取指令,而是讀取內(nèi)存中這個回調(diào)函數(shù)的地址。所以刪除這些動態(tài)加載的JS文件是沒有問題的。
所謂 ID 和路徑匹配原則 是指,使用 seajs.use 或 require 進行引用的文件,如果是具名模塊(即定義了 ID 的模塊),會把 ID 和 seajs.use 的路徑名進行匹配,如果一致,則正確執(zhí)行模塊返回結(jié)果。反之,則返回 null。
對 module.exports 的賦值需要同步執(zhí)行,不能放在回調(diào)函數(shù)里。下面這樣是不行的// x.js define(function(require, exports, module) { // 錯誤用法 setTimeout(function() { module.exports = { a: "hello" }; }, 0); }); //在 y.js 里有調(diào)用到上面的 x.js: // y.js define(function(require, exports, module) { var x = require("./x"); // 無法立刻得到模塊 x 的屬性 a console.log(x.a); // undefined });
WilsonLiu"s blog首發(fā)地址:http://blog.wilsonliu.cn
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79775.html
摘要:二模塊化規(guī)范概述應(yīng)用由模塊組成,采用模塊規(guī)范。模塊化語法命令用于規(guī)定模塊的對外接口,命令用于輸入其他模塊提供的功能。 前言 在JavaScript發(fā)展初期就是為了實現(xiàn)簡單的頁面交互邏輯,寥寥數(shù)語即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端(表單驗證等),隨著web2.0時代的到來,Ajax技術(shù)得到廣泛應(yīng)用,jQuery等前端庫層出不窮,前端代碼日益膨脹,此時...
摘要:二模塊化規(guī)范概述應(yīng)用由模塊組成,采用模塊規(guī)范。模塊化語法命令用于規(guī)定模塊的對外接口,命令用于輸入其他模塊提供的功能。 前言 在JavaScript發(fā)展初期就是為了實現(xiàn)簡單的頁面交互邏輯,寥寥數(shù)語即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端(表單驗證等),隨著web2.0時代的到來,Ajax技術(shù)得到廣泛應(yīng)用,jQuery等前端庫層出不窮,前端代碼日益膨脹,此時...
摘要:前端個靈魂拷問,徹底搞明白你就是中級前端工程師上篇感覺大家比較喜歡看這種類型的文章,以后會多一些。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。此規(guī)范其實是在推廣過程中產(chǎn)生的。 showImg(https://segmentfault.com/img/bVbwAMU?w=700&h=394); 前端20個靈魂拷問,徹底搞明白你就是中級前端工程師...
摘要:前端個靈魂拷問,徹底搞明白你就是中級前端工程師上篇感覺大家比較喜歡看這種類型的文章,以后會多一些。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。此規(guī)范其實是在推廣過程中產(chǎn)生的。 showImg(https://segmentfault.com/img/bVbwAMU?w=700&h=394); 前端20個靈魂拷問,徹底搞明白你就是中級前端工程師...
閱讀 738·2021-11-22 13:54
閱讀 3142·2021-09-26 10:16
閱讀 3554·2021-09-08 09:35
閱讀 1615·2019-08-30 15:55
閱讀 3457·2019-08-30 15:54
閱讀 2105·2019-08-30 10:57
閱讀 522·2019-08-29 16:25
閱讀 899·2019-08-29 16:15