検索
ホームページウェブフロントエンドjsチュートリアルJavaScript モジュラー プログラミングのローダー原理の詳細な説明

sea.js、require.js、yuiloader、labJs...など、世の中にはJavaScriptローダーがたくさんありますが、ローダーの利用範囲は比較的大きなプロジェクト向けだと個人的には感じています。小規模なプロジェクトでは不要な場合があります。私は seaJS と requireJS を使用しました。requireJS は AMD に準拠しており、その正式名は (Asynchronous Module Definition) であり、seaJS の非同期モジュール読み込みメカニズムです。 CMD仕様に準拠したローダーです。

AMD__ と __CMD

AMD 仕様は依存関係フロントローディング、CMD 仕様は依存関係ポストロードで、AMD 仕様のローダーは JS 内のすべての依存関係をフロントローディングで実行します。 CMD は遅延ロードです。JS がこのモジュールを必要とする場合はロードされます。そうでない場合は、AMD 仕様に準拠したローダー (requireJS) によって引き起こされる問題により、初回ロードに時間がかかる場合があります。依存する JS をすべてロードするので、一度にダウンロードします。

常識的には、jQuery は AMD 仕様をサポートしますが、CMD 仕様はサポートしません。つまり、seaJS を導入して jQuery を使用したい場合は、エイリアス設定を使用する必要があります。または直接 http://www .php.cn/ ページに直接導入;

//这是jQuery源码的最后几行, jQuery到了1.7才支持模块化;
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// http://www.php.cn/
if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    });
};

使用方法

たとえば、次のようなモジュールを定義できます:

//文件所在的路径地址为:http://www.php.cn/:63342/module/script/dir2/1.js
define(function() {
    return "!!!!";
});

また、次のようなモジュールを定義することもできます:

//这个文件的路径为http://www.php.cn/:63342/module/main.js ,
而且有一个依赖, 加载器会自动去加载这个依赖, 当依赖加载完毕以后, 会把这个依赖(就是script/dir2/1.js)执行的返回值作为这个函数的参数传进去;
require(["script/dir2/1.js"], function(module1) {
    console.log(module1);
});
//实际上会打印出 "!!!!"

一般的に、モジュールは 1 つの定義関数のみを記述できます。定義関数にパラメータを渡すには主に 2 つの方法があります:

1: 通常は関数にすることができます。

2: 配列型のリストにすることができます。依存関係と関数;

モジュールが複数の定義を記述すると、モジュールが誤動作し、最初に定義されたモジュールが後で定義されたモジュールによって上書きされます (もちろん、通常はそのように動作しません)。

複数の require を 1 つのモジュールに記述することができ、require を匿名の定義モジュールとして直接理解できます。1 つの定義モジュール内に複数の require が存在する可能性があり、このキャッシュされた変数は通常

closure にキャッシュされます。 、そしてほとんどの名前はモジュールと呼ばれます...;

私たちはローダーを使用します モジュール開発は標準に準拠する必要があります。モジュールが JS として標準化されている場合、コントローラー、ビュー、モデル用にいくつかの新しいディレクトリを作成できます。これは、将来のメンテナンスと分離を改善するためでもあります:

独自のローダーを実装します

使用方法:

//这个模块依赖的四个模块,加载器会分别去加载这四个模块;
define(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3){

});

//返回一个空对象
define(function(){
    return {};
});

//直接把require当作是define来用就好了;
require(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3) {
    //执行依赖0;
    依赖0(依赖1,依赖2,依赖3);
});

//这个加载器define函数和require函数的区别是,define我们可以传个name作为第一参数, 这个参数就是模块的名字, 好吧, 不管这些了.....;

以下は、コードの量が非常に少ないため、すべての関数のローダーの構造です。世界的な状況に影響を与えないために、コードは自己実行関数内に匿名で配置されます:

(function() {
    定义一个局部的difine;
    var define;
    //我偷偷加了个全局变量,好调试啊;
    window.modules = {
    };
    //通过一个名字获取绝对路径比如传"xx.js"会变成"http://www.mm.com/"+ baseUrl + "xx.html";
    var getUrl = function(src) {};
    //动态加载js的模块;
    var loadScript = function(src) {};
    //获取根路径的方法, 一般来说我们可以通过config.baseUrl配置这个路径;
    var getBasePath = function() {};
    //获取当前正在加载的script标签DOM节点;
    var getCurrentNode = function() {};
    //获取当前script标签的绝对src地址;
    var getCurrentPath = function() {};
    //加载define或者require中的依赖, 封装了loadScript方法;
    var loadDpt = function(module) {};
    //这个是主要模块, 完成了加载依赖, 检测依赖等比较重要的逻辑
    var checkDps = function() {};
    定义了define这个方法
    define = function(deps, fn, name) {};
    window.define = define;
    //require是封装了define的方法, 就是多传了一个参数而已;
    window.require = function() {
        //如果是require的话那么模块的名字就是一个不重复的名字,避免和define重名;
        window.define.apply([], Array.prototype.slice.call(arguments).concat( "module|"+setTimeout(function() {},0) ));
    };
});

Loader ソース コード実装 (chrome、FF、IE6 ==>> IE11 と互換性あり)、IE11 はそうします。これは詐欺であり、readyState 属性も currentScript 属性もありません。また、現在実行中の JS のパスを取得できないため、ハックを使用してください。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
    (function() {
        var define;
        window.modules = {
        };
        var getUrl = function(src) {
            var scriptSrc = "";
            //判断URL是否是
            // ./或者
            // /或者
            // 直接是以字符串开头
            // 或者是以http://开头;
            if( src.indexOf("/") === 0 || src.indexOf("./") === 0 ) {
                scriptSrc = require.config.base + src.replace(/^\//,"").replace(/^\.\//,"");
            }else if( src.indexOf("http:") === 0 ) {
                scriptSrc = src;
            }else if( src.match(/^[a-zA-Z1-9]/) ){
                scriptSrc = require.config.base + src;
            }else if(true) {
                alert("src错误!");
            };
            if (scriptSrc.lastIndexOf(".js") === -1) {
                scriptSrc += ".js";
            };
            return scriptSrc;
        };

        var loadScript = function(src) {
            var scriptSrc = getUrl(src);
            var sc = document.createElement("script");
            var head = document.getElementsByTagName("head")[0];
            sc.src = scriptSrc;
            sc.onload = function() {
                console.log("script tag is load, the url is : " + src);
            };
            head.appendChild( sc );
        };

        var getBasePath = function() {
            var src = getCurrentPath();
            var index = src.lastIndexOf("/");
            return  src.substring(0,index+1);
        };

        var getCurrentNode = function() {
            if(document.currentScript) return document.currentScript;
            var arrScript = document.getElementsByTagName("script");
            var len = arrScript.length;
            for(var i= 0; i<len; i++) {
                if(arrScript[i].readyState === "interactive") {
                    return arrScript[i];
                };
            };

            //IE11的特殊处理;
            var path = getCurrentPath();
            for(var i= 0; i<len; i++) {
                if(path.indexOf(arrScript[i].src)!==-1) {
                    return arrScript[i];
                };
            };
            throw new Error("getCurrentNode error");
        };

        var getCurrentPath = function() {
            var repStr = function(str) {
                return (str || "").replace(/[\&\?]{1}[\w\W]+/g,"") || "";
            };
            if(document.currentScript) return repStr(document.currentScript.src);

            //IE11没有了readyState属性, 也没有currentScript属性;
            // 参考 http://www.php.cn/
            var stack
            try {
                a.b.c() //强制报错,以便捕获e.stack
            } catch (e) { //safari的错误对象只有line,sourceId,sourceURL
                stack = e.stack
                if (!stack && window.opera) {
                    //opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
                    stack = (String(e).match(/of linked script \S+/g) || []).join(" ")
                }
            }
            if (stack) {
                /**e.stack最后一行在所有支持的浏览器大致如下:
                 *chrome23:
                 * at http://www.php.cn/:4:1
                 *firefox17:
                 *@http://www.php.cn/:4
                 *opera12:http://www.php.cn/
                 *@http://www.php.cn/:4
                 *IE10:
                 *  at Global code (http://www.php.cn/:4:1)
                 *  //firefox4+ 可以用document.currentScript
                 */
                stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分
                stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符
                return stack.replace(/(:\d+)?:\d+$/i, "") //去掉行号与或许存在的出错字符起始位置
            };

            //实在不行了就走这里;
            var node = getCurrentNode();
            //IE>=8的直接通过src可以获取,IE67要通过getAttriubte获取src;
            return repStr(document.querySelector ? node.src : node.getAttribute("src", 4)) || "";

            throw new Error("getCurrentPath error!");
        };

        var loadDpt = function(module) {
            var dp = "";
            for(var p =0; p<module.dps.length; p++) {
                //获取绝对的地址;
                var dp = getUrl(module.dps[p]);
                //如果依赖没有加载就直接加载;
                if( !modules[dp] ) {
                    loadScript(dp);
                };
            };
        };

        //主要的模块, 检测所有未加载的模块中未完成了的依赖是否加载完毕,如果加载完毕就加载模块, 如果加载过的话,而且所有依赖的模块加载完毕就执行该模块
        //而且此模块的exports为该模块的执行结果;
        var checkDps = function() {
            for(var key in modules ) {
                //初始化该模块需要的参数;
                var params = [];
                var module = modules[key];
                //加载完毕就什么都不做;
                if( module.state === "complete" ) {
                    continue;
                };
                if( module.state === "initial" ) {
                    //如果依赖没有加载就加载依赖并且modules没有该module就加载这个模块;
                    loadDpt(module);
                    module.state = "loading";
                };
                if( module.state === "loading") {
                    //如果这个依赖加载完毕
                    for(var p =0; p<module.dps.length; p++) {
                        //获取绝对的地址;
                        var dp = getUrl(module.dps[p]);
                        //如果依赖加载完成了, 而且状态为complete;;
                        if( modules[dp] && modules[dp].state === "complete") {
                            params.push( modules[dp].exports );
                        };
                    };
                    //如果依赖全部加载完毕,就执行;
                    if( module.dps.length === params.length ) {
                        if(typeof module.exports === "function"){
                            module.exports = module.exports.apply(modules,params);
                            module.state = "complete";
                            //每一次有一个模块加载完毕就重新检测modules,看看是否有未加载完毕的模块需要加载;
                            checkDps();
                        };
                    };
                };
            };
        };

        //[],fn; fn
        define = function(deps, fn, name) {
            if(typeof deps === "function") {
                fn = deps;
                deps = [];//我们要把数组清空;
            };

            if( typeof deps !== "object" && typeof fn !== "function") {
                alert("参数错误")
            };

            var src = getCurrentPath();
            //没有依赖, 没有加载该模块就新建一个该模块;
            if( deps.length===0 ) {
                modules[ src ] = {
                    name : name || src,
                    src : src,
                    dps : [],
                    exports : (typeof fn === "function")&&fn(),
                    state : "complete"
                };
                return checkDps();
            }else{
                modules[ src ] = {
                    name : name || src,
                    src : src,
                    dps : deps,
                    exports : fn,
                    state : "initial"
                };
                return checkDps();
            }
        };

        window.define = define;
        window.require = function() {
            //如果是require的话那么模块的名字就是一个不重复的名字,避免和define重名;
            window.define.apply([], Array.prototype.slice.call(arguments).concat( "module|"+setTimeout(function() {},0) ));
        };
        require.config = {
            base : getBasePath()
        };
        require.loadScript = loadScript;
        var loadDefaultJS = getCurrentNode().getAttribute("data-main");
        loadDefaultJS && loadScript(loadDefaultJS);
    })();
    </script>
</head>
<body>
</body>
</html>

Ye Dada から盗まれたローダー。このローダーは、の実装に少し似ています。 jQuery の遅延オブジェクト ($.Deferred) に関連するメソッド when($.when);

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        (function () {

            //存储已经加载好的模块
            var moduleCache = {};

            var define = function (deps, callback) {
                var params = [];
                var depCount = 0;
                var i, len, isEmpty = false, modName;

                //获取当前正在执行的js代码段,这个在onLoad事件之前执行
                modName = document.currentScript && document.currentScript.id || &#39;REQUIRE_MAIN&#39;;

                //简单实现,这里未做参数检查,只考虑数组的情况
                if (deps.length) {
                    for (i = 0, len = deps.length; i < len; i++) {
                        (function (i) {
                            //依赖加一
                            depCount++;
                            //这块回调很关键
                            loadMod(deps[i], function (param) {
                                params[i] = param;
                                depCount--;
                                if (depCount == 0) {
                                    saveModule(modName, params, callback);
                                }
                            });
                        })(i);
                    }
                } else {
                    isEmpty = true;
                }

                if (isEmpty) {
                    setTimeout(function () {
                        saveModule(modName, null, callback);
                    }, 0);
                }

            };

            //考虑最简单逻辑即可
            var _getPathUrl = function (modName) {
                var url = modName;
                //不严谨
                if (url.indexOf(&#39;.js&#39;) == -1) url = url + &#39;.js&#39;;
                return url;
            };

            //模块加载
            var loadMod = function (modName, callback) {
                var url = _getPathUrl(modName), fs, mod;

                //如果该模块已经被加载
                if (moduleCache[modName]) {
                    mod = moduleCache[modName];
                    if (mod.status == &#39;loaded&#39;) {
                        setTimeout(callback(this.params), 0);
                    } else {
                        //如果未到加载状态直接往onLoad插入值,在依赖项加载好后会解除依赖
                        mod.onload.push(callback);
                    }
                } else {

                    /*
                     这里重点说一下Module对象
                     status代表模块状态
                     onLoad事实上对应requireJS的事件回调,该模块被引用多少次变化执行多少次回调,通知被依赖项解除依赖
                     */
                    mod = moduleCache[modName] = {
                        modName: modName,
                        status: &#39;loading&#39;,
                        export: null,
                        onload: [callback]
                    };

                    _script = document.createElement(&#39;script&#39;);
                    _script.id = modName;
                    _script.type = &#39;text/javascript&#39;;
                    _script.charset = &#39;utf-8&#39;;
                    _script.async = true;
                    _script.src = url;

                    //这段代码在这个场景中意义不大,注释了
                    //      _script.onload = function (e) {};

                    fs = document.getElementsByTagName(&#39;script&#39;)[0];
                    fs.parentNode.insertBefore(_script, fs);

                }
            };

            var saveModule = function (modName, params, callback) {
                var mod, fn;

                if (moduleCache.hasOwnProperty(modName)) {
                    mod = moduleCache[modName];
                    mod.status = &#39;loaded&#39;;
                    //输出项
                    mod.export = callback ? callback(params) : null;

                    //解除父类依赖,这里事实上使用事件监听较好
                    while (fn = mod.onload.shift()) {
                        fn(mod.export);
                    }
                } else {
                    callback && callback.apply(window, params);
                }
            };

            window.require = define;
            window.define = define;

        })();
    </script>
</head>
<body>
</body>
</html>

MVC の小さな例を書きます。 コードは単純で、専門家は無視できます。 ディレクトリ構造は次のとおりです。次のように:

すべてのイベントをcontroller/mainController.jsに配置し、

define(["model/data","view/view0"],function(data, view) {
    var init = function() {
        var body = document.getElementsByTagName("body")[0];
        var aBtn = document.getElementsByTagName("button");
        for(var i=0; i< aBtn.length; i++) {
            aBtn[i].onclick = (function(i) {
                return function() {
                    body.appendChild( view.getView(data[i]) );
                };
            })(i);
        };
    };
    return {
        init : init
    };
});

すべてのデータをモデル/data.jsに配置します。

define(function() {
    return [
        {name : "qihao"},
        {name : "nono"},
        {name : "hehe"},
        {name : "gege"}
    ];
})
ビューのJSはビューディレクトリに配置されます。 view0.js は主に HTML 文字列または DOM ノードの生成を担当します。

define(function() {
    return {
        getView : function(data) {
            var frag = document.createDocumentFragment();
                frag.appendChild( document.createTextNode( data.name + " ") );
            return frag;
        }
    }
});

入り口は、load.html と同じディレクトリである app.js です:

require(["controller/mainController"],function( controller ) {
    controller.init();
});

load.html これがメインのインターフェイスです:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title></head>
<body>
<button>0</button>
<button>1</button>
<button>2</button>
<button>3</button>
<script src="require.js" data-main="app.js"></script>
</body>
</html>

上記は、JavaScript モジュラー プログラミングのローダー原理の詳細な説明です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python vs. Javascript:どの言語を学ぶべきですか?Python vs. Javascript:どの言語を学ぶべきですか?May 03, 2025 am 12:10 AM

PythonまたはJavaScriptの選択は、キャリア開発、学習曲線、エコシステムに基づいている必要があります。1)キャリア開発:Pythonはデータサイエンスとバックエンド開発に適していますが、JavaScriptはフロントエンドおよびフルスタック開発に適しています。 2)学習曲線:Python構文は簡潔で初心者に適しています。 JavaScriptの構文は柔軟です。 3)エコシステム:Pythonには豊富な科学コンピューティングライブラリがあり、JavaScriptには強力なフロントエンドフレームワークがあります。

JavaScriptフレームワーク:最新のWeb開発のパワーJavaScriptフレームワーク:最新のWeb開発のパワーMay 02, 2025 am 12:04 AM

JavaScriptフレームワークのパワーは、開発を簡素化し、ユーザーエクスペリエンスとアプリケーションのパフォーマンスを向上させることにあります。フレームワークを選択するときは、次のことを検討してください。1。プロジェクトのサイズと複雑さ、2。チームエクスペリエンス、3。エコシステムとコミュニティサポート。

JavaScript、C、およびブラウザの関係JavaScript、C、およびブラウザの関係May 01, 2025 am 12:06 AM

はじめに私はあなたがそれを奇妙に思うかもしれないことを知っています、JavaScript、C、およびブラウザは正確に何をしなければなりませんか?彼らは無関係であるように見えますが、実際、彼らは現代のウェブ開発において非常に重要な役割を果たしています。今日は、これら3つの間の密接なつながりについて説明します。この記事を通して、JavaScriptがブラウザでどのように実行されるか、ブラウザエンジンでのCの役割、およびそれらが協力してWebページのレンダリングと相互作用を駆動する方法を学びます。私たちは皆、JavaScriptとブラウザの関係を知っています。 JavaScriptは、フロントエンド開発のコア言語です。ブラウザで直接実行され、Webページが鮮明で興味深いものになります。なぜJavascrを疑問に思ったことがありますか

node.jsは、型を使用してストリーミングしますnode.jsは、型を使用してストリーミングしますApr 30, 2025 am 08:22 AM

node.jsは、主にストリームのおかげで、効率的なI/Oで優れています。 ストリームはデータを段階的に処理し、メモリの過負荷を回避します。大きなファイル、ネットワークタスク、リアルタイムアプリケーションの場合。ストリームとTypeScriptのタイプの安全性を組み合わせることで、パワーが作成されます

Python vs. JavaScript:パフォーマンスと効率の考慮事項Python vs. JavaScript:パフォーマンスと効率の考慮事項Apr 30, 2025 am 12:08 AM

PythonとJavaScriptのパフォーマンスと効率の違いは、主に以下に反映されています。1)解釈された言語として、Pythonはゆっくりと実行されますが、開発効率が高く、迅速なプロトタイプ開発に適しています。 2)JavaScriptはブラウザ内の単一のスレッドに限定されていますが、マルチスレッドおよび非同期I/Oを使用してnode.jsのパフォーマンスを改善でき、両方とも実際のプロジェクトで利点があります。

JavaScriptの起源:その実装言語の調査JavaScriptの起源:その実装言語の調査Apr 29, 2025 am 12:51 AM

JavaScriptは1995年に発信され、Brandon Ikeによって作成され、言語をCに実現しました。 2。JavaScriptのメモリ管理とパフォーマンスの最適化は、C言語に依存しています。 3. C言語のクロスプラットフォーム機能は、さまざまなオペレーティングシステムでJavaScriptを効率的に実行するのに役立ちます。

舞台裏:JavaScriptをパワーする言語は何ですか?舞台裏:JavaScriptをパワーする言語は何ですか?Apr 28, 2025 am 12:01 AM

JavaScriptはブラウザとnode.js環境で実行され、JavaScriptエンジンに依存してコードを解析および実行します。 1)解析段階で抽象的構文ツリー(AST)を生成します。 2)ASTをコンパイル段階のバイトコードまたはマシンコードに変換します。 3)実行段階でコンパイルされたコードを実行します。

PythonとJavaScriptの未来:傾向と予測PythonとJavaScriptの未来:傾向と予測Apr 27, 2025 am 12:21 AM

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません