ホームページ  >  記事  >  ウェブフロントエンド  >  JS のフロントエンドのモジュール性の詳細な分析とその違いの比較

JS のフロントエンドのモジュール性の詳細な分析とその違いの比較

不言
不言オリジナル
2018-08-13 17:34:321781ブラウズ

この記事は、JS でのフロントエンドのモジュール化の詳細な分析と比較を提供します。必要な方は参考にしていただければ幸いです。

質問の投げかけ:

  • 開発では、モジュールをインポートするときに requireimport がよく使用されます。 requireimport

  • 导出模块时使用module.exports/exports或者export/export default;

  • 有时候为了引用一个模块会使用require奇怪的是也可以使用import????它们之间有何区别呢?

于是有了菜鸟解惑的搜喽过程。。。。。

追溯根源,来到Js模块化规范

1、CommonJS规范(同步加载模块)

  • 允许模块通过require方法来同步加载所要依赖的其他模块,然后通过exports或module.exports来导出需要暴露的接口。

  • 使用方式:

// 导入
require("module");
require("../app.js");
// 导出
exports.getStoreInfo = function() {};
module.exports = someValue;
    • 因为模块都放在服务器端,对于服务端来说模块加载时

    • 而对于浏览器端,因为模块都放在服务器端,加载的时间还取决于网速的快慢等因素,如果需要等很长时间,整个应用就会被阻塞。

    • 因此,浏览器端的模块,不能采用"同步加载"(CommonJs),只能采用"异步加载"(AMD)。

    • 优点:

    • 缺点:

    • 为什么浏览器不能使用同步加载,服务端可以?

  1. 同步加载方式不适合在浏览器环境中使用,同步意味着阻塞加载,浏览器资源是异步加载的

  2. 不能非阻塞的并行加载多个模块

  1. 简单容易使用

  2. 服务器端模块便于复用

  • 参照CommonJs模块代表node.js的模块系统

AMD(异步加载模块)

  • 采用异步方式加载模块,模块的加载不影响后面语句的运行。所有依赖模块的语句,都定义在一个回调函数中,等到加载完成之后,回调函数才执行。

  • 使用实例:

// 定义
define("module", ["dep1", "dep2"], function(d1, d2) {...});
// 加载模块
require(["module", "../app"], function(module, app) {...});
  • 加载模块require([module], callback);第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback是加载成功之后的回调函。

  • 优点:

  1. 适合在浏览器环境中异步加载模块

  2. 可以并行加载多个模块

  • 缺点:

    1. 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅

    2. 不符合通用的模块化思维方式,是一种妥协的实现

  • 实现AMD规范代表require.js

  • モジュールをエクスポートするときに module を使用します。 /exports または export/exportdefault;
    • モジュールを参照するために、require が使用される場合があります。奇妙なことに、import も使用できます。 コード>? ? ? ?それらの違いは何ですか? <p></p>
    そのため、新人が疑問を解決するための検索プロセスが存在します。 。 。 。 。
    1. 根本原因をたどり、Js モジュラー仕様に行き着きます

      1. CommonJS 仕様 (モジュールの同期ロード)
    2. を使用すると、モジュールが依存する他のモジュールを同期的にロードできます。 require メソッドを使用してから、exports または module.exports を使用して、公開する必要があるインターフェイスをエクスポートします。
    3. 使い方:

    define(function(require, exports, module) {
      var a = require('./a');
      a.doSomething();
      // 依赖就近书写,什么时候用到什么时候引入
      var b = require('./b');
      b.doSomething();
    });

    • モジュールはサーバー側に配置されるため、サーバー側の場合はモジュールがロードされるとき

    • そしてブラウザ側の場合、モジュールはサーバー側に配置され、ロードにかかる時間はネットワークの速度などの要因にも依存します。長時間待機する必要がある場合、アプリケーション全体がブロックされます。

    • したがって、ブラウザ側モジュールは「同期読み込み」(CommonJs)を使用できず、「非同期読み込み」(AMD)のみを使用できます。

    1. メリット:

    2. デメリット:

    3. ? なぜブラウザは同期読み込みを使用できないのに、サーバーは同期読み込みを使用できるのでしょうか?

    同期読み込みメソッドは、ブラウザ環境での使用には適していません。
  • 🎜 は、ブロックせずに複数のファイルを並行して読み込みます。モジュール🎜🎜🎜🎜🎜🎜シンプルで使いやすい🎜🎜🎜🎜サーバー側モジュールは再利用が簡単です🎜🎜🎜🎜🎜🎜node.jsのモジュールシステムを表すにはCommonJsモジュールを参照してください🎜🎜🎜🎜AMD(非同期ロードモジュール)🎜 🎜🎜🎜 モジュールは非同期でロードされ、モジュールのロードは後続のステートメントの実行に影響を与えません。モジュールに依存するすべてのステートメントはコールバック関数で定義されます。コールバック関数はロードが完了するまで実行されません。 🎜🎜🎜🎜使用例: 🎜🎜🎜
    // AMD
    define(['./a', './b'], function(a, b) {  // 依赖必须一开始就写好  
       a.doSomething()    
       // 此处略去 100 行    
       b.doSomething()    
       ...
    });
    // CMD
    define(function(require, exports, module) {
       var a = require('./a')   
       a.doSomething()   
       // 此处略去 100 行   
       var b = require('./b') 
       // 依赖可以就近书写   
       b.doSomething()
       // ... 
    });
    🎜🎜🎜Load module require([module], callback);最初のパラメータ[module]は配列であり、内部のメンバーがロードされますmodule; 2 番目のパラメータ callback は、ロードが成功した後のコールバック関数です。 🎜🎜🎜🎜 利点: 🎜🎜🎜🎜🎜 ブラウザ環境でのモジュールの非同期ロードに適しています 🎜🎜🎜🎜 複数のモジュールを並行してロードできます 🎜🎜🎜🎜🎜 欠点: 🎜🎜🎜 🎜🎜 開発コストの増加、コードの読み取り書くのが難しく、モジュール定義メソッドのセマンティクスがスムーズではなく、一般的なモジュールの考え方に準拠しておらず、モジュールに対する 🎜🎜🎜🎜RequireJS の態度は実行前です。 RequireJS は実装された AMD 仕様であるため、すべての依存モジュールが最初に実行されます。つまり、RequireJS は依存モジュールを事前に実行します。これは、require 🎜🎜🎜🎜RequireJS 実行プロセスを進めることと同等です。依存モジュール、設定ファイルに従って js ファイルの実際のパスを取得します🎜🎜🎜🎜js ファイルの実際のパスに従って、dom にスクリプト ノードを挿入し、onload イベントをバインドして、モジュールがロードされています。 🎜🎜🎜🎜すべての依存スクリプトがロードされた後、コールバック関数を呼び出します 🎜🎜🎜🎜CMD仕様(非同期ロードモジュール) 🎜🎜🎜🎜CMD仕様はAMDに非常に似ており、シンプルで、CommonJSとNodeのモジュール仕様を維持します.js CMD 仕様では優れた互換性があり、モジュールはファイルです。 🎜🎜🎜🎜定義モジュールは、ファクトリパラメータを受け取るグローバル関数defineを使用します。🎜🎜🎜🎜factoryは、function(require、exports、module)の3つのパラメータを持つ関数です。 ): 🎜🎜🎜🎜🎜require は、他のモジュールによって提供されるインターフェースを取得するための唯一のパラメーターとしてモジュール ID を受け入れるメソッドです: require(id)🎜🎜🎜🎜exports は、モジュールインターフェースを外部に提供するために使用されるオブジェクトです 🎜 🎜🎜🎜module は、現在のモジュールに関連付けられたいくつかのプロパティとメソッドを保存するオブジェクトです 🎜🎜🎜🎜🎜インスタンス: 🎜
  • define(function(require, exports, module) {
      var a = require('./a');
      a.doSomething();
      // 依赖就近书写,什么时候用到什么时候引入
      var b = require('./b');
      b.doSomething();
    });
    • 优点:

    1. 依赖就近,延迟执行

    2. 可以很容易在 Node.js 中运行

    • 缺点:

    1. 依赖 SPM 打包,模块的加载逻辑偏重

    • 实现代表库sea.js:SeaJS对模块的态度是懒执行, SeaJS只会在真正需要使用(依赖)模块时才执行该模块

    AMD 与 CMD 的区别

    1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从2.0开始,也改成了可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

    2. AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require。

    // AMD
    define(['./a', './b'], function(a, b) {  // 依赖必须一开始就写好  
       a.doSomething()    
       // 此处略去 100 行    
       b.doSomething()    
       ...
    });
    // CMD
    define(function(require, exports, module) {
       var a = require('./a')   
       a.doSomething()   
       // 此处略去 100 行   
       var b = require('./b') 
       // 依赖可以就近书写   
       b.doSomething()
       // ... 
    });

    UMD

    • UMD是AMD和CommonJS的糅合

    • AMD 以浏览器第一原则发展异步加载模块。

    • CommonJS 模块以服务器第一原则发展,选择同步加载,它的模块无需包装。

    • UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式;在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。

    (function (window, factory) {
        if (typeof exports === 'object') {
        
            module.exports = factory();
        } else if (typeof define === 'function' && define.amd) {
        
            define(factory);
        } else {
        
            window.eventUtil = factory();
        }
    })(this, function () {
        //module ...
    });

    ES6模块化

    • ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

    • ES6 模块设计思想:尽量的静态化、使得编译时就能确定模块的依赖关系,以及输入和输出的变量(CommonJS和AMD模块,都只能在运行时确定这些东西)。

      • 使用方式:

    // 导入
    import "/app";
    import React from “react”;
    import { Component } from “react”;
    // 导出
    export function multiply() {...};
    export var year = 2018;
    export default ...
    ...
    • 优点:

    1. 容易进行静态分析

    2. 面向未来的 EcmaScript 标准

    • 缺点:

    1. 原生浏览器端还没有实现该标准

    2. 全新的命令字,新版的 Node.js才支持。

    回到问题“require与import的区别”

    • require使用与CommonJs规范,import使用于Es6模块规范;所以两者的区别实质是两种规范的区别;

    • CommonJS:

    1. 对于基本数据类型,属于复制。即会被模块缓存;同时,在另一个模块可以对该模块输出的变量重新赋值。

    2. 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。

    3. 当使用require命令加载某个模块时,就会运行整个模块的代码。

    4. 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。

    5. 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。

    • ES6模块

    1. ES6模块中的值属于【动态只读引用】。

    2. 对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。

    3. 对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。

    4. 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。

    • 最後に: require/exports は必要であり、普遍的で必要です。実際、これまでに作成した import/exports は最終的に実行のために require/exports にコンパイルされるからです。

    関連する推奨事項: ページ間のデータ転送を実装するための

    js コード

    JS チュートリアル - 動的計画アルゴリズムのナップザック容量問題

    JavaScript のスコープとクロージャーに関する知識の説明

    以上がJS のフロントエンドのモジュール性の詳細な分析とその違いの比較の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。