日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

seajs的CMD模式的优势以及使用

發布時間:2025/3/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 seajs的CMD模式的优势以及使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前有一篇博客非常詳細的介紹了sea.js的加載流程,以及源代碼實現,鏈接地址:http://www.cnblogs.com/chaojidan/p/4123980.html

這篇博客我主要講下sea.js的介紹和使用。

首先,先介紹下sea.js的CMD規范,以及跟其他規范的區別。

CommonJS 原來叫 ServerJS,推出?Modules/1.0?規范后,在 Node.js 等環境下取得了很不錯的實踐。

09年下半年這幫充滿干勁的小伙子們想把 ServerJS 的成功經驗進一步推廣到瀏覽器端,于是將社區改名叫 CommonJS,同時激烈爭論 Modules 的下一版規范。分歧和沖突由此誕生,逐步形成了三大流派:

  • Modules/1.x 流派。這個觀點覺得 1.x 規范已經夠用,只要移植到瀏覽器端就好。主流代表是服務端的開發人員。
  • Modules/Async 流派。這個觀點覺得瀏覽器有自身的特征,不應該直接用 Modules/1.x 規范。這個觀點下的典型代表是?AMD?規范及其實現?RequireJS。
  • Modules/2.0 流派。這個觀點覺得瀏覽器有自身的特征,不應該直接用 Modules/1.x 規范,但應該盡可能與 Modules/1.x 規范保持一致。這個觀點下的典型代表是?BravoJS?和 FlyScript 的作者。BravoJS 作者對 CommonJS 的社區的貢獻很大,這份?Modules/2.0-draft?規范花了很多心思。FlyScript 的作者提出了?Modules/Wrappings?規范,這規范是 CMD 規范的前身。可惜的是 BravoJS 太學院派,FlyScript 后來做了自我閹割,將整個網站(flyscript.org)下線了。
  • 第二流派:AMD 與 RequireJS

    AMD 風格下,通過參數傳入依賴模塊,破壞了就近聲明 (需要時,才聲明)原則。比如:

    define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {? ??? // 等于在最前面聲明并初始化了要用到的所有模塊 ?? if (false) { ?????? // 即便沒用到某個模塊 b,但 b 還是提前執行了 ?????? b.foo() ?? }? })

    第三流派:Modules/2.0  CMD模塊

    CMD 里,默認推薦的是

    define(function(require, exports, module) { //a,b模塊只下載好了,并且只執行了模塊中的define方法,而define方法中的function要等到require時,才會執行 ? var a = require('a'); //延遲執行了a,b模塊 ? var b = require('b'); ? // do sth })

    ?

    區別:

    1. 對于依賴的模塊,AMD 是提前執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改成可以延遲執行(根據寫法不同,處理方式不同)。CMD 推崇 as lazy as possible.

    2. CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼:

    // CMD

    define(function(require, exports, module) {

      var a = require('./a');

      a.doSomething()

      //此處略去 100 行

      var b = require('./b')

      // 依賴可以就近書寫

      b.doSomething();

    })

    // AMD 默認推薦的是

      define(['./a', './b'], function(a, b) {

        // 依賴必須一開始就寫好

        a.doSomething();

       // 此處略去 100 行

        b.doSomething();

      })?

    雖然 AMD 也支持 CMD 的寫法,同時還支持將 require 作為依賴項傳遞,但 RequireJS 的作者默認是最喜歡上面的寫法,也是官方文檔里默認的模塊定義寫法。

    3. AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一

    比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啟動。CMD 里,每個 API 都簡單純粹

    CMD 可以使得構建時的復雜度降低。

    目前 Sea.js 擁有 plugin-combo 插件,模塊的合并可以放在線上動態做。有些情況下(比較容易出現),動態 combo 的地址會很長:

    https://a.alipaybojects.com/??path/to/a.js,path/to/b.js..................path/to/long-url.js

    當 url 地址很長時,超過 2083(好像是這個值),在 IE 以及一些服務器配置下,過長的 url 會出問題。這時經典的解決辦法是將 url 拆分成多段:

    https://a.alipaybojects.com/??path/to/a.js,path/to/b.js..................path/to/u.js

    https://a.alipaybojects.com/??path/to/f.js,path/to/g.js..................path/to/long-url.js

    拆分后,在 CMD 規范下,上面兩個 url 可以并發同時請求,誰先返回都沒問題。但在 AMD 下,上面的需求,就掛了,很難實現。

    你會說 RequireJS 鼓勵的是項目上線前,通過構建工具先構建好,不需要線上 combo,也就不會遇到上面的問題。

    Sea.js 放得更寬泛,提前合并好,還是線上時才動態 combo,對 CMD 模塊來說都可行。很多時候,combo 真心省事,也更自然。前端開發并非處處要像 Java 一樣引入嚴格的構建過程。

    CMD 的懶執行策略,也更有利于頁面性能。

    RequireJS 2.0 后,不少理念也在悄悄地發生著變化,現在好像也支持懶執行了。

    ?

    然后,介紹下sea.js的方法和使用。

    type="text/javascript" src="js/seajs/2.0.0/sea-debug.js?t=123" data-config="sea-js-config.js?t=123"

    上面的data-config是指sea.js的配置文件的路徑。還有一個屬性是data-main,它是項目的起始模塊,如果定義了會先執行此模塊。data-main是可選項。

    首先我們來看看sea-js-config.js

    seajs.config({
    ? ?  // 配置插件
    ? ?plugins: ['shim'],
    ? ?  // 配置別名
    ? ?alias: {
    ? ? ?  // 配置 jquery 的 shim 配置,這樣我們就可以通過 require('jquery') 來獲取 jQuery
    ? ?  'jquery': {
    ? ? ? ?   src: 'libs/jquery/1.9.1/jquery.js',  //注意,這里是從sea.js所在目錄的上兩節目錄開始查找文件
    ? ? ? ? ?  ?exports: 'jQuery'
    ? ? ? ?}
    ? ?}
    });

    plugins選項配置插件,這里使用了shim插件。由于jquery不是一個標準的CMD模塊,所以直接加載jquery是錯誤的。這里使用了shim插件,會自動把jquery轉換成一個標準的CMD模塊。不用人工改動jquery源碼。alias是配置別名,方便加載的。

    看個例子:


    項目主模塊app.js
    define(function(require, exports, module) {
        //加載jquery, 并把它$設為全局變量
    ?  window.$ = window.jQuery = $ = require('jquery');
    ?     //定義一個全局的模塊加載函數.module為模塊名,options為參數
    ?   exports.script_load = function(module, options) {
    ? ? ??  //使用require.async異步加載模塊。模塊需要提供一個固定的對外調用接口,這里定義為run。
    ? ? ?   require.async('modules/' + module, function(module) {
    ?      if (typeof(module.run) === 'function') {
    ? ? ? ? ? ? ?     module.run(options);
    ?      }
    ? ? ? ?  });
    ?   }
    ?   window.script_load = exports.script_load
    });
    上面我們加載了jquery, 并且定義了一個模塊加載函數。現在我們在html頁面加入如下代碼:
    <script type="text/javascript">
    ? ? ?seajs.use('modules/app', function(app) {
    ? ? ? ? ?  app.script_load('index');
      });
    </script>
    use方法執行時,會先加載app模塊,加載并執行完后,就進入function中,這時就會調用app.script_load方法,此方法就會去加載index模塊,加載完成后,執行index中的代碼,index中會返回run方法。index執行完畢后,會調用require.async的回調方法:

    if (typeof(module.run) === 'function') {
    ? ? ? ? ? ? ?     module.run(options);
    }

    因此index模塊中返回了run方法,因此就執行index中的run方法。

    index.js
    define(function(require, exports, module) {
    ?  exports.run = function() {
    ? ? ?    $('#alert').click(function() {
            alert('彈出了一個框!');
    ? ? ?    });
      }
    });

    ?

    SeaJS中使用“define”函數定義一個模塊,define可以接收三個參數,
    define可以接收的參數分別是模塊ID,依賴模塊數組及工廠函數。
    我閱讀源代碼后發現define對于不同參數個數的解析規則如下:
    如果只有一個參數,則賦值給factory。
    如果有兩個參數,第二個賦值給factory;第一個如果是array則賦值給deps,否則賦值給id。
    如果有三個參數,則分別賦值給id,deps和factory。
    id是一個模塊的標識字符串,define只有一個參數時,id會被默認賦值為此js文件的絕對路徑。
    如example.com下的a.js文件中使用define定義模塊,則這個模塊的ID會賦值為 http://example.com/a.js ,沒有特別的必要建議不要傳入id。deps一般也不需要傳入,需要用到的模塊用require加載即可。
    工廠函數function是模塊的主體和重點。在只傳遞一個參數給define時(推薦寫法),這個參數就是工廠函數,此時工廠函數的三個參數分別是:
    ? require——模塊加載函數,用于記載依賴模塊。
    ? exports——接口點,將數據或方法定義在其上則將其暴露給外部調用。
    ? module——模塊的元數據。
    module是一個對象,存儲了模塊的元信息,具體如下:
    ? module.id——模塊的ID。
    ? module.dependencies——一個數組,存儲了此模塊依賴的所有模塊的ID列表。
    ? module.exports——與exports指向同一個對象。

    ?

    三種編寫模塊的模式:

    第一種定義模塊的模式是基于exports的模式:

    define(function(require, exports, module) {
      var a = require('a'); //引入a模塊
    ? ? ?var b = require('b'); //引入b模塊

    ? ? ?var data1 = 1; //私有數據

      var func1 = function() { //私有方法
        return a.run(data1);
      }

    ? ? ?exports.data2 = 2; //公共數據

    ? ? ?exports.func2 = function() { //公共方法
        return 'hello';
      }
    });

    上面是一種比較“正宗”的模塊定義模式。除了將公共數據和方法附加在exports上,也可以直接返回一個對象表示模塊,如下面的代碼與上面的代碼功能相同:(第二種)

    define(function(require, exports, module) {
      var a = require('a'); //引入a模塊
    ? ? ?var b = require('b'); //引入b模塊

    ? ? ?var data1 = 1; //私有數據

      var func1 = function() { //私有方法
        return a.run(data1);
      }

    ?  return {
        data2: 2,
    ? ? ? ? ? ?func2: function() {
    ? ? ? ? ? ? ?  return 'hello';
        }
      };

    });

    如果模塊定義沒有其它代碼,只返回一個對象,還可以有如下簡化寫法。第三種方法對于定義純JSON數據的模塊非常合適。

    define({

    ????data: 1,

    ????func: function() {

    ????????return 'hello';

    ? ?}

    });

    ?

    絕對地址——給出js文件的絕對路徑。如

    require("http://example/js/a");

    就代表載入?http://example/js/a.js?。

    基址地址——如果載入字符串標識既不是絕對路徑也不是以”./”開頭的相對地址,則相對SeaJS全局配置中的“base”來尋址。

    注意上面在載入模塊時都不用傳遞后綴名“.js”,SeaJS會自動添加“.js”。但是下面三種情況下不會添加:

    載入css時,如

    require("./module1-style.css");

    路徑中含有”?”時,如

    require(<a href="http://example/js/a.json?cb=func">http://example/js/a.json?cb=func</a>);

    路徑以”#”結尾時,如

    require("http://example/js/a.json#");

    根據應用場景的不同,SeaJS提供了三個載入模塊的API,分別是seajs.use,require和require.async。

    seajs.use主要用于載入入口模塊。入口模塊相當于C程序的main函數,同時也是整個模塊依賴樹的根。seajs.use用法如下:

    //單一模式

    seajs.use('./a');

    //回調模式

    seajs.use('./a', function(a) {

    ??  a.run();

    });

    //多模塊模式

    seajs.use(['./a', './b'], function(a, b) {

    ? ? a.run();

      b.run();

    ?});

    一般seajs.use只用在頁面載入入口模塊,SeaJS會順著入口模塊解析所有依賴模塊并將它們加載。如果入口模塊只有一個,也可以通過給引入sea.js的script標簽加入”data-main”屬性來省略seajs.use,例如,

    <!DOCTYPE HTML>

    <html lang="zh-CN">

    <head>

      <meta charset="UTF-8">

    ?<title>TinyApp</title>

    </head>

    <body>

    ?  <p class="content"></p>

    ?  <script src="./sea.js" data-main="./init"></script>

    </body>

    </html>

    ?

    傳給require的路徑標識必須是字符串字面量,不能是表達式,如下面使用require的方法是錯誤的:
    ?require('module' + '1');
    ?require('Module'.toLowerCase());
    這都會造成SeaJS無法進行正確的正則匹配以下載相應的js文件。
    上文說過SeaJS會在html頁面打開時通過靜態分析,一次性下載所有需要的js文件,如果想要某個js文件在用到時才下載,可以使用require.async。

    require.async('/path/to/module/file', function(m) {
      //code of callback...
    });
    這樣只有在用到這個模塊時,對應的js文件才會被下載,也就實現了JavaScript代碼的按需加載。

    SeaJS提供了一個seajs.config方法可以設置全局配置,接收一個表示全局配置的配置對象。
    seajs.config({
      base: 'path/to/jslib/',
      alias: {
    ? ? ? ?  'app': 'path/to/app/'
      },
      charset: 'utf-8',
      timeout: 20000,
      debug: false
    });
    其中base表示基址尋址時的基址路徑。例如base設置為 http://example.com/js/3-party/ ,則
    var $ = require('jquery');
    會載入 http://example.com/js/3-party/jquery.js 。
    alias可以對較長的常用路徑設置縮寫。
    charset表示下載js時script標簽的charset屬性。
    timeout表示下載文件的最大時長,以毫秒為單位。
    debug表示是否工作在調試模式下。
    要將現有JS庫如jQuery與SeaJS一起使用,只需根據SeaJS的的模塊定義規則對現有庫進行一個封裝。例如,下面是對jQuery的封裝方法:
    define(function() {

    ?  //{{{jQuery原有代碼開始

      ?//}}}jQuery原有代碼結束

    ?  return $.noConflict();
    });

    ?

    特別注意:下面這種寫法是錯誤的!
    define(function(require, exports) {

      // 錯誤用法!!!
      exports = {
        foo: 'bar',
        doSomething: function() {}
      };

    });
    正確的寫法是用 return 或者給 module.exports 賦值:
    define(function(require, exports, module) {

      // 正確寫法
      module.exports = {
        foo: 'bar',
        doSomething: function() {}
      };

    });
    提示:exports 僅僅是 module.exports 的一個引用。在 factory 內部給 exports 重新賦值時,并不會改變 module.exports 的值。因此給 exports 賦值是無效的,不能用來更改模塊接口。
    傳給 factory 構造方法的 exports 參數是 module.exports 對象的一個引用。

    只通過 exports 參數來提供接口,有時無法滿足開發者的所有需求。 比如當模塊的接口是某個類的實例時,需要通過module.exports 來實現:
    define(function(require, exports, module) {

      // exports 是 module.exports 的一個引用
      console.log(module.exports === exports);?// true

      // 重新給 module.exports 賦值
      module.exports = new SomeClass(); ? ??//當模塊的接口是某個類的實例時

      // exports 不再等于 module.exports
      console.log(module.exports === exports);?// false

    });
    注意:對 module.exports 的賦值需要同步執行,不能放在回調函數里。下面這樣是不行的:

    define(function(require, exports, module) {

      // 錯誤用法
      setTimeout(function() {
        module.exports = { a: "hello" };
      }, 0);

    });
    seajs.config({
      alias: {
      'jquery': 'jquery/1.7.2/jquery-debug.js'
    }
    });

    seajs.use(['./a','jquery'],function(a,$){
      var num = a.a;
      $('#J_A').text(num);
    })

    use方法將會從我們的config配置信息中查看 ,是否有預先需要被加載的模塊。如果有,就先加載,沒有就加載a和jquery模塊。

    轉載于:https://www.cnblogs.com/chaojidan/p/4147925.html

    總結

    以上是生活随笔為你收集整理的seajs的CMD模式的优势以及使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。