接著上文的學(xué)習(xí)以及嘗試實現(xiàn),準(zhǔn)備好好看下源碼的實現(xiàn)。
var requirejs, require, define;
(function (global, setTimeout){...}(this ,setTimeout));
整體結(jié)構(gòu)就是放出了3個全局的變量,然后在一個匿名函數(shù)中對3個變量進行賦值。這里把this和setTimeout傳進去應(yīng)該是歷史原因,怕這些東西被改寫
然互看匿名函數(shù)的整體的結(jié)構(gòu):
- 最先申明了一些簡寫以及使用到的正則以及瀏覽器屬性的判斷。
- 然后申明了一些簡單的輔助方法,包括一些循環(huán),還有對象的檢測。
- 然后是一個主要的方法newContext。這個很長,慢慢看。
- 然后申明了require方法
- 然后調(diào)用了req({});進行了最初的初始化
- 然后遍歷拿到script,來得到data-main的入口,與我的寫法一樣
- 然后申明了define方法
- 然后再執(zhí)行了一次req(cfg);用配置好的cfg
執(zhí)行的主要流程
主要是就是執(zhí)行了一次req({});然后初始化了cfg,然后再執(zhí)行了一次req(cfg)。
這里函數(shù)執(zhí)行的比較復(fù)雜,我花了一些時間畫了一個圖,畫的精疲力盡:
requirejs.png
圖里面其實已經(jīng)畫的很詳細(xì)了,我的圖只是其中一種執(zhí)行的順序,簡單總結(jié)就是
- 第一次req()初始化環(huán)境
- 第二次req()開始加載入口的模塊
- define函數(shù)實際上往全局的隊列推入
- 模塊加載好了會執(zhí)行onScriptLoad方法,然后進行一層層的事件通知(注意事件是綁在依賴的模塊上的,出發(fā)后,執(zhí)行父模塊的回調(diào),然后再emit調(diào)用父模塊的回調(diào))
- 內(nèi)部還是有輪詢在不斷的檢查時候加載好的,我個人感覺是為了處理error事件,他本身的加載過程并不依賴與這個輪詢
- 他內(nèi)部支持commonjs的方式其實就是用個正則表達(dá)式來進行檢索,然后推入deps正常加載,換了個形式騙騙人..
小的tip
nextTick里面的4ms是因為html5的規(guī)范要求的
順便給個github的傳送門,喜歡的朋友star一下啊,自己平時遇到的問題以及一下學(xué)習(xí)的思考都會在上面記錄~
參考:
http://www.cnblogs.com/yexiaochai/p/3632580.html
http://www.cnblogs.com/zhiyishou/p/4770013.html
http://www.nihaoshijie.com.cn/index.php/archives/381