在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ AMD
中介者模式
MVVM
亨元模式
設(shè)計模式分類概覽表
ES Harmony
組合模式
CommonJS
jQuery 插件的設(shè)計模式
外觀模式
觀察者模式
建造者模式
構(gòu)造器模式
外觀模式
簡介
AMD
原型模式
設(shè)計模式的分類
觀察者模式
命名空間模式
代理模式
編寫設(shè)計模式
適配器模式
反模式
什么是設(shè)計模式
模塊化模式
MVC
Mixin 模式
裝飾模式
設(shè)計模式的結(jié)構(gòu)
單例模式
迭代器模式
命令模式
工廠模式
MVP
暴露模塊模式
惰性初始模式

AMD

在瀏覽器中編寫模塊化Javascript的格式

AMD (異步模塊定義Asynchronous Module Definition)格式的最終目的是提供一個當(dāng)前開發(fā)者能使用的模塊化Javascript方案。它出自于Dojo用XHR+eval的實踐經(jīng)驗,這種格式的支持者想在以后的項目中避免忍受過去的這些弱點。

AMD模塊格式本身是模塊定義的一個建議,通過它模塊本身和模塊之間的引用可以被異步的加載。它有幾個明顯的優(yōu)點,包括異步的調(diào)用和本身的高擴展性,它實現(xiàn)了解耦,模塊在代碼中也可通過識別號進行查找。當(dāng)前許多開發(fā)者都喜歡使用它,并且認為它朝ES Harmony提出模塊化系統(tǒng) 邁出了堅實的一步。

最開始AMD在CommonJs的列表中是作為模塊化格式的一個草案,但是由于它不能達到與模塊化完全一致,更進一步的開發(fā)被移到了在amdjs組中。

現(xiàn)在,它包含工程Dojo、MooTools、Firebug以及jQuery。盡管有時你會看見CommonJS AMD 格式化術(shù)語,但最好的和它相關(guān)的是AMD或者是異步模塊支持,同樣不是所有參與到CommonJS列表的成員都希望與它產(chǎn)生關(guān)系。

注意:曾有一段時間涉及Transport/C模塊的提議規(guī)劃沒有面向已經(jīng)存在的CommonJS模塊,但是對于定義模塊來說,它對選擇AMD命名空間約定產(chǎn)生了影響。

從模塊開始

關(guān)于AMD值得特別注意的兩個概念就是:一個幫助定義模塊的define方法和一個處理依賴加載的require方法。define被用來通過下面的方式定義命名的或者未命名的模塊:

define(
    module_id /*可選的*/,
    [dependencies] /*可選的*/,
    definition function /*用來實例化模塊或者對象的方法*/
);

通過代碼中的注釋我們可以發(fā)現(xiàn),module_id 是可選的,它通常只有在使用非AMD連接工具的時候才是必須的(可能在其它不是特別常見的情況下,它也是有用的)。當(dāng)不存在module_id參數(shù)的時候,我們稱這個模塊為匿名模塊。

當(dāng)使用匿名模塊的時候,模塊認定的概念是DRY的,這樣使它在避免文件名和代碼重復(fù)的時候顯得很微不足道。因為這樣一來代碼方便切換,你可以很容易地把它移動到其它地方(或者文件系統(tǒng)的其他位置),而不需要更改代碼內(nèi)容或者它的模塊ID。你可以認為模塊id跟文件路徑的概念是相似的。

注意:開發(fā)者們可以將同樣的代碼放到不同的環(huán)境中運行,只要他們使用一個在CommonJS環(huán)境下工作的AMD優(yōu)化器(比如r.js)就可以了。

在回來看define方法簽名, dependencies參數(shù)代表了我們正在定義的模塊需要的dependency數(shù)組,第三個參數(shù)("definition function" or "factory function") 是用來執(zhí)行的初始化模塊的方法。 一個正常的模塊可以像下面那樣定義:

Understanding AMD: define()

// A module_id (myModule) is used here for demonstration purposes only
define( "myModule",

    ["foo", "bar"],

    // module definition function
    // dependencies (foo and bar) are mapped to function parameters
    function ( foo, bar ) {
        // return a value that defines the module export
        // (i.e the functionality we want to expose for consumption)

        // create your module here
        var myModule = {
            doStuff:function () {
                console.log( "Yay! Stuff" );
            }
        };

    return myModule;
});

// An alternative version could be..
define( "myModule",

    ["math", "graph"],

    function ( math, graph ) {

        // Note that this is a slightly different pattern
        // With AMD, it's possible to define modules in a few
        // different ways due to it's flexibility with
        // certain aspects of the syntax
        return {
            plot: function( x, y ){
                return graph.drawPie( math.randomGrid( x, y ) );
            }
        };
});

另一方面,require被用來從一個頂級文件或者模塊里加載代碼,而這是我們原本就希望的動態(tài)加載依賴的位置。它的一個用法如下:

理解AMD: require()

// Consider "foo" and "bar" are two external modules
// In this example, the "exports" from the two modules
// loaded are passed as function arguments to the
// callback (foo and bar) so that they can similarly be accessed

require(["foo", "bar"], function ( foo, bar ) {
        // rest of your code here
        foo.doSomething();
});

動態(tài)加載依賴

define(function ( require ) {
    var isReady = false, foobar;

    // note the inline require within our module definition
    require(["foo", "bar"], function ( foo, bar ) {
        isReady = true;
        foobar = foo() + bar();
    });

    // we can still return a module
    return {
        isReady: isReady,
        foobar: foobar
    };
});

理解 AMD: 插件

下面是定義一個兼容AMD插件的例子:

// With AMD, it's possible to load in assets of almost any kind
// including text-files and HTML. This enables us to have template
// dependencies which can be used to skin components either on
// page-load or dynamically.

define( ["./templates", "text!./template.md","css!./template.css" ],

    function( templates, template ){
        console.log( templates );
        // do something with our templates here
    }

});

注意:盡管上面的例子中css!被包含在在加載CSS依賴的過程中,要記住,這種方式有一些問題,比如它不完全可能在CSS完全加載的時候建立模塊. 取決于我們?nèi)绾螌崿F(xiàn)創(chuàng)建過程,這也可能導(dǎo)致CSS被作為優(yōu)化文件中的依賴被包含進來,所以在這些情況下把CSS作為已加載的依賴應(yīng)該多加小心。如果你對上面的做法感興趣,我們也可以從這里查看更多@VIISON的RequireJS CSS 插件:https://github.com/VIISON/RequireCSS

使用RequireJS加載AMD模塊

require(["app/myModule"],

    function( myModule ){
        // start the main module which in-turn
        // loads other modules
        var module = new myModule();
        module.doStuff();
});

這個例子可以簡單地看出asrequirejs(“app/myModule”,function(){})已被加載到頂層使用。這就展示了通過AMD的define()函數(shù)加載到頂層模塊的不同,下面通過一個本地請求allrequire([])示例兩種類型的裝載機(curl.js和RequireJS)。

使用curl.js加載AMD模塊

curl(["app/myModule.js"],

    function( myModule ){
        // start the main module which in-turn
        // loads other modules
        var module = new myModule();
        module.doStuff();

});

延遲依賴模塊

// This could be compatible with jQuery's Deferred implementation,
// futures.js (slightly different syntax) or any one of a number
// of other implementations

define(["lib/Deferred"], function( Deferred ){
    var defer = new Deferred();

    require(["lib/templates/?index.html","lib/data/?stats"],
        function( template, data ){
            defer.resolve( { template: template, data:data } );
        }
    );
    return defer.promise();
});

使用Dojo的AMD模塊

使用Dojo定義AMD兼容的模塊是相當(dāng)直接的.如上所述,就是在一個數(shù)組中定義任何的模塊依賴作為第一個參數(shù),并且提供回調(diào)函數(shù)來執(zhí)行一次依賴已經(jīng)被加載進來的模塊.例如:

define(["dijit/Tooltip"], function( Tooltip ){

    //Our dijit tooltip is now available for local use
    new Tooltip(...);

});

請注意模塊的匿名特性,現(xiàn)在它可以在一個Dojo匿名裝載裝置中的被處理,RequireJS或者標(biāo)準(zhǔn)的dojo.require()模塊裝載器。

了解一些有趣的關(guān)于模塊引用的陷阱是非常有用的.雖然AMD倡導(dǎo)的引用模塊的方式宣稱它們在一組帶有一些匹配參數(shù)的依賴列表里面,這在版本更老的Dojo 1.6構(gòu)建系統(tǒng)中并不被支持--它真的僅僅對AMD兼容的裝載器才起作用.例如:

define(["dojo/cookie", "dijit/Tooltip"], function( cookie, Tooltip ){

    var cookieValue = cookie( "cookieName" );
    new Tooltip(...);

});

越過嵌套的命名空間定義方式有許多好處,模塊不再需要每一次都直接引用完整的命名空間了--所有我們所需要的是依賴中的"dojo/cookie"路徑,它一旦賦給一個作為別名的參數(shù),就可以用變量來引用了.這移除了在我們的應(yīng)用程序中重復(fù)打出"dojo."的必要。

最后需要注意到的難點是,如果我們希望繼續(xù)使用更老的Dojo構(gòu)建系統(tǒng),或者希望將老版本的模塊遷移到更新的AMD形式,接下來更詳細的版本會使得遷移更加容易.注意dojo和dijit也是作為依賴被引用的:

define(["dojo", "dijit', "dojo/cookie", "dijit/Tooltip"], function( dojo, dijit ){
    var cookieValue = dojo.cookie( "cookieName" );
    new dijit.Tooltip(...);
});

AMD 模塊設(shè)計模式 (Dojo)

正如在前面的章節(jié)中,設(shè)計模式在提高我們的結(jié)構(gòu)化構(gòu)建的共同開發(fā)問題非常有效。 John Hann已經(jīng)給AMD模塊設(shè)計模式,涵蓋單例,裝飾,調(diào)解和其他一些優(yōu)秀的設(shè)計模式,如果有機會,我強烈建議參考一下他的 幻燈片。 AMD設(shè)計模式的選擇可以在下面找到。

一段AMD設(shè)計模式可以在下面找到。

修飾設(shè)計模式

// mylib/UpdatableObservable: dojo/store/Observable的一個修飾器
define(["dojo", "dojo/store/Observable"], function ( dojo, Observable ) {
    return function UpdatableObservable ( store ) {

        var observable = dojo.isFunction( store.notify ) ? store :
                new Observable(store);

        observable.updated = function( object ) {
            dojo.when( object, function ( itemOrArray) {
                dojo.forEach( [].concat(itemOrArray), this.notify, this );
            });
        };

        return observable;
    };
});

// 修飾器消費者
// mylib/UpdatableObservable的消費者

define(["mylib/UpdatableObservable"], function ( makeUpdatable ) {
    var observable,
        updatable,
        someItem;

    // 讓observable 儲存 updatable
    updatable = makeUpdatable( observable ); // `new` 關(guān)鍵字是可選的!

    // 如果我們想傳遞修改過的data,我們要調(diào)用.update()
    //updatable.updated( updatedItem );
});

適配器設(shè)計模式

// "mylib/Array" 適配`each`方法來模仿 jQuerys:
define(["dojo/_base/lang", "dojo/_base/array"], function ( lang, array ) {
    return lang.delegate( array, {
        each: function ( arr, lambda ) {
            array.forEach( arr, function ( item, i ) {
                lambda.call( item, i, item ); // like jQuery's each
            });
        }
    });
});

// 適配器消費者
// "myapp/my-module":
define(["mylib/Array"], function ( array ) {
    array.each( ["uno", "dos", "tres"], function ( i, esp ) {
        // here, `this` == item
    });
});

使用jQuery的AMD模塊

不像Dojo,jQuery真的存在于一個文件中,而是基于插件機制的庫,我們可以在下面代碼中證明AMD模塊是如何直線前進的。

define(["js/jquery.js","js/jquery.color.js","js/underscore.js"],

    function( $, colorPlugin, _ ){
        // <span></span>這里,我們通過jQuery中,顏色的插件,并強調(diào)沒有這些將可在全局范圍內(nèi)訪問,但我們可以很容易地在下面引用它們。
        // 偽隨機一系列的顏色,在改組后的數(shù)組中選擇的第一個項目 

 <div>

 </div>
        var shuffleColor = _.first( _.shuffle( "#666","#333","#111"] ) );

        // 在頁面上有class為"item" 的元素隨機動畫改變背景色
        $( ".item" ).animate( {"backgroundColor": shuffleColor } );

        // 我們的返回可以被其他模塊使用
        return {};
    });

然而,這個例子中缺失了一些東西,它只是注冊的概念。

將jQuery當(dāng)做一個異步兼容的模塊注冊

jQuery1.7中落實的一個關(guān)鍵特性是支持將jQuery當(dāng)做一個異步兼容的模塊注冊。有很多兼容的腳本加載器(包括RequireJS 和 curl)可以使用異步模塊形式加載模塊,而這意味著在讓事物起作用的時候,更少的需要使用取巧的特殊方法。

如果開發(fā)者想要使用AMD,并且不想將他們的jQuery的版本泄露到全局空間中,他們就應(yīng)該在使用了jQuery的頂層模塊中調(diào)用noConflict方法.另外,由于多個版本的jQuery可能在一個頁面上,AMD加載器就必須作出特殊的考慮,以便jQuery只使用那些認識到這些問題的AMD加載器來進行注冊,這是使用加載器特殊的define.amd.jQuery來表示的。RequireJS和curl是兩個這樣做了的加載器。

這個叫做AMD的家伙提供了一種安全的魯棒的封包,這個封包可以用于絕大多數(shù)情況。

// Account for the existence of more than one global
// instances of jQuery in the document, cater for testing
// .noConflict()

var jQuery = this.jQuery || "jQuery",
$ = this.$ || "$",
originaljQuery = jQuery,
original$ = $;

define(["jquery"] , function ( $ ) {
    $( ".items" ).css( "background","green" );
    return function () {};
});

為什么AMD是寫模塊化Javascript代碼的好幫手呢?

  • 提供了一個清晰的方案,告訴我們?nèi)绾味x一個可擴展的模塊。
  • 和我們常用的前面的全局命名空間以及 <script> 標(biāo)簽解決方案相比較,非常清晰。有一個清晰的方式用于聲明獨立的模塊,以及它們所依賴的模塊。
  • 模塊定義被封裝了,有助于我們避免污染全局命名空間。
  • 比其它替代方案能更好的工作(例如CommonJS,后面我們就會看到)。沒有跨域問題,局部以及調(diào)試問題,不依賴于服務(wù)器端工具。大多數(shù)AMD加載器支持在瀏覽器中加載模塊,而不需要構(gòu)建過程。
  • 提供一個“透明”的方法用于在單個文件中包含多個模塊。其它方式像 CommonJS 要求必須遵循一個傳輸格式。 再有需要的時候,可以惰性加載腳本。

注意:上面的很多說法也可以說做事YUI模塊加載策略。

相關(guān)閱讀

有哪些腳本加載器或者框架支持AMD?

瀏覽器端:

(and more)

服務(wù)器端:

AMD 總結(jié)

在很多項目中使用過AMD,我的結(jié)論就是AMD符合了很多條一個構(gòu)建嚴肅應(yīng)用的開發(fā)者所想要的一個好的模塊的格式要求。不用擔(dān)心全局,支持命名模塊,不需要服務(wù)端轉(zhuǎn)換來工作,在依賴管理中也很方便。

同時也是使用Bacbon.js,ember.js 或者其它結(jié)構(gòu)化框架來開發(fā)模塊時的利器,可以保持項目的組織架構(gòu)。 在Dojo和CommonJS世界中,AMD已經(jīng)被討論了兩年了,我們直到它需要時間去逐漸成熟和進化。我們也知道在外面有很多大公司也在實戰(zhàn)中使用了AMD用于構(gòu)建非凡的系統(tǒng)(IBM, BBC iPlayer),如果它不好,那么可能現(xiàn)在它們就已經(jīng)被丟棄了,但是沒有。

但是,AMD依然有很多地方有待改善。使用這些格式一段時間的開發(fā)者可能已經(jīng)感受到了AMD 樣板和封裝代碼很討厭。盡管我也有這樣的憂慮,但是已經(jīng)存在一些工具例如Volo 可以幫助我們繞過這些問題,同時我也要說整體來看,AMD的優(yōu)勢遠遠勝過其缺點。

上一篇:觀察者模式下一篇:適配器模式