首頁  >  文章  >  web前端  >  Js中前端模組化的詳細分析及其區別對比

Js中前端模組化的詳細分析及其區別對比

不言
不言原創
2018-08-13 17:34:321761瀏覽

這篇文章帶給大家的內容是關於Js中前端模組化的詳細分析及其區別對比,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

拋出問題:

  • 在開發中在匯入模組時經常使用requireimport

  • 匯出模組時使用module.exports/exportsexport/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

  • RequireJS對模組的態度是預先執行。由於RequireJS 是執行的AMD 規範, 因此所有的依賴模組都是先執行;即RequireJS是預先把依賴的模組執行,相當於把require提前了
    • RequireJS執行流程:

    1. require函數檢查依賴的模組,根據設定文件,取得js檔案的實際路徑

    2. ##根據js文件實際路徑,在dom中插入script節點,並綁定onload事件來取得該模組載入完成的通知。

    3. 依賴script全部載入完成後,呼叫回呼函數

    #CMD規格(非同步載入模組)

    • CMD規範和AMD很相似,簡單,並與CommonJS和Node.js的Modules 規範保持了很大的兼容性;在CMD規範中,一個模組就是一個文件。

    • 定義模組使用全域函數define,其接收factory 參數,factory 可以是函數,也可以是物件或字串;

    • factory 是函數,有三個參數,function(require, exports, module):

    1. require 是方法,接受模組識別為唯一參數,用來取得其他模組提供的介面:require(id)

    2. exports 是一個對象,用來向外提供模組介面

    3. 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/export 最終都是編譯為 require/exports 來執行的。

    相關推薦:

    js實作頁間資料傳遞的程式碼

    JS教學--動態規劃演算法背包容量問題

    關於javaScript中作用域與閉包的知識講解

    以上是Js中前端模組化的詳細分析及其區別對比的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn