RequireJS源碼初探

来源:http://www.cnblogs.com/xing901022/archive/2016/04/17/5401195.html
-Advertisement-
Play Games

前兩天跟著葉小釵的博客,看了下RequireJS的源碼,大體瞭解了其中的執行過程。不過在何時進行依賴項的載入,以及具體的代碼在何處執行,還沒有搞透徹,奈何能力不夠,只能先記錄一下了。 RequireJS的初探 看源碼從頭開始看,肯定是不切實際的。按照葉小釵的方法,是從data main開始的,所以我 ...


前兩天跟著葉小釵的博客,看了下RequireJS的源碼,大體瞭解了其中的執行過程。不過在何時進行依賴項的載入,以及具體的代碼在何處執行,還沒有搞透徹,奈何能力不夠,只能先記錄一下了。

RequireJS的初探

看源碼從頭開始看,肯定是不切實際的。按照葉小釵的方法,是從data-main開始的,所以我們也從那裡開始把!

首先,頁面會有一段js標簽,會去載入requirejs:

<script data-main="test.js" src="lib/require.js"></script>

Requirejs中,代碼是一個自執行的方法:

var requirejs,require,define;
(function(global){
    
})(this);

源碼中,主要是定義了三個全局的變數——requirejs,require,define,下麵是一個自執行的方法。

那麼主要就是看看這個方法裡面都幹了什麼吧!

RequireJS主體方法

//定義環境變數

    //定義各種方法

    //檢查requirejs,require,define

    //核心部分
    function newContext(){}//定義核心部分方法
    
    req = requirejs = function(){//定義req
        //...
        return context.require();
    };

    req.config = function(){};

    req({});//創建預設的上下文

    req.createNode = function (config, moduleName, url) {
        var node = config.xhtml ?
                document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
                document.createElement('script');
        node.type = config.scriptType || 'text/javascript';
        node.charset = 'utf-8';
        node.async = true;
        return node;
    };

    //洋洋灑灑,載入代碼
    req.load = function(){
        node = req.createNode(config, moduleName, url);//創建節點
        node.addEventListener('load', context.onScriptLoad, false);//添加load事件
        if (baseElement) {//插入到head裡面
            head.insertBefore(node, baseElement);
        } else {
            head.appendChild(node);
        }
    };

    if (isBrowser && !cfg.skipDataMain) {
        //載入main.js
    }

    define = function(){};

    req.exec =function(){};

    req(cfg);//執行配置文件

上面的代碼中,關鍵的方法定義其實只有兩個:

  • 定義了newContext()方法,用於配置上下文環境,並且僅會執行一次!後續都是使用同一個context!
  • 定義req,它是後續使用的方法!

然後在上面的代碼中,它做了下麵三件事:

  • 1 執行req({}),傳入了空的對象,初始化context
  • 2 if(isBrowser && xxxx)....,載入data-main所指向的js,讀取配置
  • 3 執行req(cfg),執行剛剛讀取的配置,載入目標模塊...

基本上就是這個套路了!

newContext()

RequireJS最精彩的部分,就在這個方法裡面了!

function newContext(contextName){

    function getModule(depMap) {
        var id = depMap.id,
            mod = getOwn(registry, id);

        if (!mod) {
            mod = registry[id] = new context.Module(depMap);
        }

        return mod;
    }
    
    function checkLoaded() {
        
    }

    context = {
        //...
        makeRequire: function (relMap, options) {
            //核心
            function localRequire(deps, callback, errback) {
                //真正的核心
                context.nextTick(function () {
                    intakeDefines();

                    requireMod = getModule(makeModuleMap(null, relMap));//主要看這裡吧

                    requireMod.skipMap = options.skipMap;

                    requireMod.init(deps, callback, errback, {
                        enabled: true
                    });

                    checkLoaded();
                });
            }

            return localRequire;
        },
        load: function (id, url) {
            req.load(context, id, url);
        },
        onScriptLoad : function() {
            context.completeLoad();
        },
        completeLoad : function() {
            takeGlobalQueue();
            while(defQueue.length){

            }
            mod = getOwn(registry, moduleName);
            checkLoaded();
        }
        //...
    }

    Module.prototype = {
        init : function(depMaps, factory, errback, options){
            if (options.enabled || this.enabled) {
                this.enable();
            } else {
                this.check();
            }
        },
        fetch : function(){
            if (this.shim) {//依賴
                context.makeRequire(this.map, {
                    enableBuildCallback: true
                })(this.shim.deps || [], bind(this, function () {
                    return map.prefix ? this.callPlugin() : this.load();
                }));
            } else {
                //Regular dependency.
                return map.prefix ? this.callPlugin() : this.load();//是否包含首碼 text!xxx
            }
        },
        load: function () {
            var url = this.map.url;

            //Regular dependency.
            if (!urlFetched[url]) {
                urlFetched[url] = true;
                context.load(this.map.id, url);
            }
        },
        check : function(){
            this.fetch();
        },
        enable : function(){
            this.check();
        }
    };
    context.require = context.makeRequire();//其實是把localRequire賦值給context.require
    return context;
};

這個newContext()裡面定義大量的載入模塊、校驗、檢查等工作。可以看到這個方法,主要是定義了一個context對象和Module方法。

然後執行這個方法後,會自動調用context對象的makeRequire()方法,這個makeRequire實際上調用的又是內部定義的localRequire()。LocalRequire則是處理載入任務的核心——比如依賴的檢查,模塊的載入等等。

執行點

req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
    setTimeout(fn, 4);
} : function (fn) { fn(); };

所有的載入都會交由這個nextTick執行,暫時沒有搞清楚...

流程圖

收穫

  • 1 原來RequireJS載入模塊的時候,是檢查data-main屬性,然後去載入目標js。
  • 2 載入到目標模塊後,會按照它的依賴關係,進行載入,並且每個模塊僅會載入一次。
  • 3 載入模塊的時候,會綁定一個load事件,當載入完會觸發事件,執行該js
  • 4 腳本實際上是通過創建了頁面的script元素,然後添加到head裡面。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 字元x 字元 x\\ 反斜線字元\0n 帶有八進位值 0 的字元 n (0 <= n <= 7)\0nn 帶有八進位值 0 的字元 nn (0 <= n <= 7)\0mnn 帶有八進位值 0 的字元 mnn(0 <= m <= 3、0 <= n <= 7)\xhh 帶有十六進位值 0x 的字元 h ...
  • 對IE瀏覽器尤其是IE6的抱怨基本已進入麻痹狀態,偶爾甚至產生非常消極的想法:這個世界只有一個瀏覽器就好了,哪怕這唯一的瀏覽器就是IE6。當然,這樣的想法是非常病態的,馬上打消。本文裡面,介紹了10個很實但IE卻不支持的CSS屬性,列出這些屬性並不是為了數落IE(數落也沒用),而是你瞭解了哪些CSS ...
  • 數據綁定是在應用程式 UI 與數據源建立連接的過程。如果綁定正確數據,則當數據更改其值時,綁定到數據的UI屬性值會自動反映更改。DeviceOne支持靈活的數據綁定,使UI展示和數據可以清晰的分離。目前還不支持雙向綁定,只支持數據到展示的傳遞。使用DeviceOne開發App,你可以不使用任何數據b ...
  • 幾個知識點: HTML 指的是超文本標記語言 (Hyper Text Markup Language) HTML框架結構: <!DOCTYPE html> <html> <head> </head> <body> 此處為標簽內容 </body> </html> HTML屬性: class=“XXX” ...
  • 一、引言 之前這個系列文章已經介紹Bootstrap。由於最近項目中,前端是Asp.net MVC + KnockoutJs + Bootstrap來做的。所以我又重新開始寫這個系列。今天就讓我們來看看Web前端的MVVM框架——KnockoutJs。 二、KnockoutJs是什麼? 做.NET開 ...
  • 由於我所在的項目組一直在用gulp構建工具,而我只是在前人搭好的環境下每次運行gulp packJs來打包js,對裡面的東西全然不知,剛好最近有些時間就想自己從學學將gulp怎麼用於構建前端項目中,這樣也會對這個構建工具有一些深刻的理解。 首先,gulp是什麼?gulp是基於nodejs的自動任務運 ...
  • React是什麼?React.js 是 Facebook 推出的一個用來構建用戶界面的 JavaScript 庫。Facebook開源了React,這是該公司用於構建反應式圖形界面的JavaScript庫,已經應用於構建Instagram網站及 Facebook部分網站。最近出現了AngularJS ...
  • AngularJS 表達式 AngularJS 表達式寫在雙大括弧內:{{expression}} AngularJS 表達式把數據綁定到HTML,這與ng-bind 指令有異曲同工之妙 AngularJS 將在表達式書寫的位置輸出數據。 AngularJS 表達式很像JavaScript表達式:他 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...