亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用AmplifyJS組件配合JavaScript進(jìn)行編程的指南

 更新時(shí)間:2015年07月28日 15:16:59   作者:梁砫  
這篇文章主要介紹了使用AmplifyJS組件配合JavaScript進(jìn)行編程的指南,AmplifyJS中提供的訂閱功能十分強(qiáng)大,需要的朋友可以參考下

事件分發(fā)的作用

在為頁面添加各類交互功能時(shí),我們熟知的最簡單的做法就是為頁面元素綁定事件,然后在事件處理函數(shù)中,做我們想要做的動(dòng)作。就像這樣的代碼:

element.onclick = function(event){
  // Do anything.
};

如果我們要做的動(dòng)作不復(fù)雜,那么實(shí)際邏輯功能的代碼,放在這里是可以的。如果今后需要修改,再到這段事件處理函數(shù)的位置來修改。

再進(jìn)一步,為了做適當(dāng)?shù)拇a復(fù)用,我們可能會(huì)把邏輯功能中的一部分分拆到一個(gè)函數(shù)內(nèi):

element.onclick = function(event){
  // Other code here.
  doSomethingElse();
};

這里的函數(shù)doSomethingElse對(duì)應(yīng)的功能可能會(huì)在其他地方用到,所以會(huì)這樣做分拆。此外,可能會(huì)有設(shè)定坐標(biāo)這樣的功能(假定函數(shù)名為setPosition),則還需要用到瀏覽器事件對(duì)象event提供的諸如指針位置一類的信息:

element.onclick = function(event){
  // Other code here.
  doSomethingElse();
  setPosition(event.clientX, event.clientY);
};

此處有一個(gè)不推薦的做法是直接把event對(duì)象傳遞給setPosition。這是因?yàn)?,分清邏輯功能和事件偵聽兩種職責(zé),是一種良好的實(shí)踐。只讓事件處理函數(shù)本身接觸到瀏覽器事件對(duì)象event,有利于降低代碼耦合,方便獨(dú)立測試及維護(hù)。

那么,功能越來越多,越來越復(fù)雜了會(huì)怎么樣呢?如果沿用之前的做法,可能是這個(gè)樣子:

element.onclick = function(event){
  doMission1();
  doMission2(event.clientX, event.clientY);
  doMission3();
  // ...
  doMissionXX();
};

雖然這樣用也沒問題,但這種時(shí)候其實(shí)就可以考慮更優(yōu)雅的寫法:

element.onclick = function(event){
  amplify.publish( "aya:clicked", {
    x: event.clientX,
    y: event.clientY
  });
};

這種形式就是事件分發(fā),請(qǐng)注意,這里的事件并不是指瀏覽器原生的事件(event對(duì)象),而是邏輯層面的自定義事件。上面的aya:clicked就是一個(gè)隨便寫(really?)的自定義事件名稱。

顯然到這還沒結(jié)束,為了完成之前的復(fù)雜的功能,我們還需要將自定義事件和要做的事關(guān)聯(lián)在一起:

amplify.subscribe( "aya:clicked", doMission1);
// ...
amplify.subscribe( "aya:clicked", doMission2);
// ...

看起來又繞了回來?沒錯(cuò),但這是有用的。一方面,瀏覽器原生事件的偵聽被分離并固化了下來,以后如果邏輯功能有變化,例如減少幾個(gè)功能,則只需要到自定義事件的關(guān)聯(lián)代碼部分做刪減,而不需要再關(guān)心原生事件。另一方面,邏輯功能的調(diào)整變得更為靈活,可以在任意的代碼位置通過subscribe添加功能,而且可以自行做分類管理(自定義的事件名)。

簡單來說,事件分發(fā)通過增加一層自定義事件的冗余(在只有簡單的邏輯功能時(shí),你就會(huì)覺得它是冗余),降低了代碼模塊之間的耦合度,使得邏輯功能更為清晰有條理,便于后續(xù)維護(hù)。

等下,前面那個(gè)出境了好幾次的很有存在感的amplify是干什么的?

Nice,終于是時(shí)候介紹這個(gè)了。
AmplifyJS

事件分發(fā)是需要一定的方法來實(shí)現(xiàn)的。實(shí)現(xiàn)事件分發(fā)的設(shè)計(jì)模式之一,就是發(fā)布/訂閱(Publish/Subscribe)。

AmplifyJS是一個(gè)簡單的JavaScript庫,主要提供了Ajax請(qǐng)求、數(shù)據(jù)存儲(chǔ)、發(fā)布/訂閱三項(xiàng)功能(每一項(xiàng)都可獨(dú)立使用)。其中,發(fā)布/訂閱是核心功能,對(duì)應(yīng)命名是amplify.core。

2015728151503102.jpg (342×85)

amplify.core是發(fā)布/訂閱設(shè)計(jì)模式的一個(gè)簡潔的、清晰的實(shí)現(xiàn),加上注釋一共100多行。讀完amplify的源碼,就可以比較好地理解如何去實(shí)現(xiàn)一個(gè)發(fā)布/訂閱的設(shè)計(jì)模式。
代碼全貌

amplify.core的源碼整體結(jié)構(gòu)如下:

(function( global, undefined ) {

var slice = [].slice,
  subscriptions = {};

var amplify = global.amplify = {
  publish: function( topic ) {
    // ...
  },

  subscribe: function( topic, context, callback, priority ) {
    // ...
  },

  unsubscribe: function( topic, context, callback ) {
    // ...
  }
};

}( this ) );

可以看到,amplify定義了一個(gè)名為amplify的全局變量(作為global的屬性),它有3個(gè)方法publish、subscribe、unsubscribe。此外,subscriptions作為一個(gè)局部變量,它將保存發(fā)布/訂閱模式涉及的所有自定義事件名及其關(guān)聯(lián)函數(shù)。
publish

publish即發(fā)布,它要求指定一個(gè)topic,也就是自定義事件名(或者就叫做話題),調(diào)用后,所有關(guān)聯(lián)到某個(gè)topic的函數(shù),都將被依次調(diào)用:

publish: function( topic ) {
  // [1]
  if ( typeof topic !== "string" ) {
    throw new Error( "You must provide a valid topic to publish." );
  }
  // [2]
  var args = slice.call( arguments, 1 ),
    topicSubscriptions,
    subscription,
    length,
    i = 0,
    ret;

  if ( !subscriptions[ topic ] ) {
    return true;
  }
  // [3]
  topicSubscriptions = subscriptions[ topic ].slice();
  for ( length = topicSubscriptions.length; i < length; i++ ) {
    subscription = topicSubscriptions[ i ];
    ret = subscription.callback.apply( subscription.context, args );
    if ( ret === false ) {
      break;
    }
  }
  return ret !== false;
},

[1],參數(shù)topic必須要求是字符串,否則拋出一個(gè)錯(cuò)誤。

[2],args將取得除topic之外的其他所有傳遞給publish函數(shù)的參數(shù),并以數(shù)組形式保存。如果對(duì)應(yīng)topic在subscriptions中沒有找到,則直接返回。

[3],topicSubscriptions作為一個(gè)數(shù)組,取得某一個(gè)topic下的所有關(guān)聯(lián)元素,其中每一個(gè)元素都包括callback及context兩部分。然后,遍歷元素,調(diào)用每一個(gè)關(guān)聯(lián)元素的callback,同時(shí)帶入元素的context和前面的額外參數(shù)args。如果任意一個(gè)關(guān)聯(lián)元素的回調(diào)函數(shù)返回false,則停止運(yùn)行其他的并返回false。
subscribe

訂閱,如這個(gè)詞自己的含義那樣(就像訂本雜志什么的),是建立topic和callback的關(guān)聯(lián)的步驟。比較特別的是,amplify在這里還加入了priority(優(yōu)先級(jí))的概念,優(yōu)先級(jí)的值越小,優(yōu)先級(jí)越高,默認(rèn)是10。優(yōu)先級(jí)高的callback,將會(huì)在publish的時(shí)候,被先調(diào)用。這個(gè)順序的原理可以從前面的publish的源碼中看到,其實(shí)就是預(yù)先按照優(yōu)先級(jí)從高到低依次排列好了某一topic的所有關(guān)聯(lián)元素。

subscribe: function( topic, context, callback, priority ) {
    if ( typeof topic !== "string" ) {
      throw new Error( "You must provide a valid topic to create a subscription." );
    }
    // [1]
    if ( arguments.length === 3 && typeof callback === "number" ) {
      priority = callback;
      callback = context;
      context = null;
    }
    if ( arguments.length === 2 ) {
      callback = context;
      context = null;
    }
    priority = priority || 10;
    // [2]
    var topicIndex = 0,
      topics = topic.split( /\s/ ),
      topicLength = topics.length,
      added;
    for ( ; topicIndex < topicLength; topicIndex++ ) {
      topic = topics[ topicIndex ];
      added = false;
      if ( !subscriptions[ topic ] ) {
        subscriptions[ topic ] = [];
      }
      // [3]
      var i = subscriptions[ topic ].length - 1,
        subscriptionInfo = {
          callback: callback,
          context: context,
          priority: priority
        };
      // [4]
      for ( ; i >= 0; i-- ) {
        if ( subscriptions[ topic ][ i ].priority <= priority ) {
          subscriptions[ topic ].splice( i + 1, 0, subscriptionInfo );
          added = true;
          break;
        }
      }
      // [5]
      if ( !added ) {
        subscriptions[ topic ].unshift( subscriptionInfo );
      }
    }

    return callback;
  },

[1],要理解這一部分,請(qǐng)看amplify提供的API示意:

amplify.subscribe( string topic, function callback )
amplify.subscribe( string topic, object context, function callback )
amplify.subscribe( string topic, function callback, number priority )
amplify.subscribe(
  string topic, object context, function callback, number priority )

可以看到,amplify允許多種參數(shù)形式,而當(dāng)參數(shù)數(shù)目和類型不同的時(shí)候,位于特定位置的參數(shù)可能會(huì)被當(dāng)做不同的內(nèi)容。這也在其他很多JavaScript庫中可以見到。像這樣,通過參數(shù)數(shù)目和類型的判斷,就可以做到這種多參數(shù)形式的設(shè)計(jì)。

[2],訂閱的時(shí)候,topic是允許空格的,空白符將被當(dāng)做分隔符,認(rèn)為是將一個(gè)callback關(guān)聯(lián)到多個(gè)topic上,所以會(huì)使用一個(gè)循環(huán)。added用作標(biāo)識(shí)符,表明新加入的這個(gè)元素是否已經(jīng)添加到數(shù)組內(nèi),初始為false。

[3],每一個(gè)callback的保存,實(shí)際是一個(gè)對(duì)象,除callback外還帶上了context(默認(rèn)為null)和priority。

[4],這個(gè)循環(huán)是在根據(jù)priority的值,找到關(guān)聯(lián)元素應(yīng)處的位置。任何topic的關(guān)聯(lián)元素都是從無到有,且依照priority數(shù)值從小到大排列(已排序的)。因此,在比較的時(shí)候,是先假設(shè)新加入的元素的priority數(shù)值較大(優(yōu)先級(jí)低),從數(shù)組尾端向前比較,只要原數(shù)組中有關(guān)聯(lián)元素的priority數(shù)值比新加入元素的小,循環(huán)就可以中斷,且可以確定地用數(shù)組的splice方法將新加入的元素添加在此。如果循環(huán)一直運(yùn)行到完畢,則可以確定新加入的元素的priority數(shù)值是最小的,此時(shí)added將保持為初始值false。

[5],如果到這個(gè)位置,元素還沒有被添加,那么執(zhí)行添加,切可以確定元素應(yīng)該位于數(shù)組的最前面(或者是第一個(gè)元素)。
unsubscribe

雖然發(fā)布和訂閱是最主要的,但也會(huì)有需要退訂的時(shí)候(雜志不想看了果斷退?。?。所以,還會(huì)需要一個(gè)unsubscribe。

unsubscribe: function( topic, context, callback ) {
  if ( typeof topic !== "string" ) {
    throw new Error( "You must provide a valid topic to remove a subscription." );
  }

  if ( arguments.length === 2 ) {
    callback = context;
    context = null;
  }

  if ( !subscriptions[ topic ] ) {
    return;
  }

  var length = subscriptions[ topic ].length,
    i = 0;

  for ( ; i < length; i++ ) {
    if ( subscriptions[ topic ][ i ].callback === callback ) {
      if ( !context || subscriptions[ topic ][ i ].context === context ) {
        subscriptions[ topic ].splice( i, 1 );
        
        // Adjust counter and length for removed item
        i--;
        length--;
      }
    }
  }
}

讀過前面的源碼后,這部分看起來就很容易理解了。根據(jù)指定的topic遍歷關(guān)聯(lián)元素,找到callback一致的,然后刪除它。由于使用的是splice方法,會(huì)直接修改原始數(shù)組,因此需要手工對(duì)i和length再做一次調(diào)整。
Amplify使用示例

官方提供的其中一個(gè)使用示例是:

amplify.subscribe( "dataexample", function( data ) {
  alert( data.foo ); // bar
});

//...

amplify.publish( "dataexample", { foo: "bar" } );

結(jié)合前面的源碼部分,是否對(duì)發(fā)布/訂閱這一設(shè)計(jì)模式有了更明確的體會(huì)呢?
補(bǔ)充說明

你可能也注意到了,AmplifyJS所實(shí)現(xiàn)的典型的發(fā)布/訂閱是同步的(synchronous)。也就是說,在運(yùn)行amplify.publish(topic)的時(shí)候,是會(huì)沒有任何延遲地把某一個(gè)topic附帶的所有回調(diào),全部都運(yùn)行一遍。
結(jié)語

Pub/Sub是一個(gè)比較容易理解的設(shè)計(jì)模式,但非常有用,可以應(yīng)對(duì)大型應(yīng)用的復(fù)雜邏輯。本文簡析的AmplifyJS是我覺得寫得比較有章法而且簡明切題(針對(duì)單一功能)的JavaScript庫,所以在此分享給大家。

相關(guān)文章

  • 從零學(xué)JSON之JSON數(shù)據(jù)結(jié)構(gòu)

    從零學(xué)JSON之JSON數(shù)據(jù)結(jié)構(gòu)

    這篇文章主要介紹了JSON數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識(shí),需要的朋友可以參考下
    2014-05-05
  • 用JavaScript獲取DOM元素位置和尺寸大小的方法

    用JavaScript獲取DOM元素位置和尺寸大小的方法

    本篇文章,小編為大家介紹關(guān)于用JavaScript獲取DOM元素位置和尺寸大小的方法,有需要的朋友可以參考一下
    2013-04-04
  • 網(wǎng)頁javascript精華代碼集

    網(wǎng)頁javascript精華代碼集

    網(wǎng)頁javascript精華代碼集...
    2007-01-01
  • 談?wù)凧avaScript中的函數(shù)與閉包

    談?wù)凧avaScript中的函數(shù)與閉包

    本篇文章,小編將與大家談?wù)凧avaScript中的函數(shù)與閉包,有需要的朋友可以參考一下
    2013-04-04
  • JavaScript中使用Math.PI圓周率屬性的方法

    JavaScript中使用Math.PI圓周率屬性的方法

    這篇文章主要介紹了JavaScript中使用Math.PI圓周率屬性的方法,是JS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-06-06
  • CentOS環(huán)境中MySQL修改root密碼方法

    CentOS環(huán)境中MySQL修改root密碼方法

    這篇文章給大家講述了如何遵循12條方法來寫出高質(zhì)量的JS代碼的經(jīng)驗(yàn),有這方便需要的朋友參考下吧。
    2018-01-01
  • 淺談javascript錯(cuò)誤處理

    淺談javascript錯(cuò)誤處理

    本文主要從前端開發(fā)者的角度談一談大多數(shù)前端開發(fā)者都會(huì)遇到的js錯(cuò)誤,對(duì)錯(cuò)誤產(chǎn)生的原因、發(fā)生階段,以及如何應(yīng)對(duì)錯(cuò)誤進(jìn)行分析、歸納和總結(jié),希望得到一些有益的結(jié)論用來指導(dǎo)日常開發(fā)工作。
    2019-08-08
  • 第一個(gè)JavaScript入門基礎(chǔ) document.write輸出

    第一個(gè)JavaScript入門基礎(chǔ) document.write輸出

    關(guān)于JavaScript,他是一個(gè)OOSP(面向?qū)ο竽_本語言)他是用來創(chuàng)建動(dòng)態(tài)網(wǎng)站,增強(qiáng)用戶界面的一門技術(shù)。如果你想了解更多關(guān)于JavaScript的信息,請(qǐng)去維基百科查詢。
    2010-02-02
  • 深入理解JS異步編程-Promise

    深入理解JS異步編程-Promise

    Promise 是 ES6 新增的一個(gè)異步解決方案,它同 await 一樣,是異步的解決方案,但是相比于 await,Promise 可以同時(shí)統(tǒng)一處理多個(gè)異步操作。這一點(diǎn)是很方便的。下面我們來一起學(xué)習(xí)一下吧
    2019-06-06
  • javascript開發(fā)技術(shù)大全 第2章 開始JAVAScript之旅

    javascript開發(fā)技術(shù)大全 第2章 開始JAVAScript之旅

    1st JavaScript Editor ,除了有著色處,還有html標(biāo)簽、屬性、javascript事件、函數(shù),另外還可調(diào)用外部編輯來編輯網(wǎng)頁,也可將常用瀏覽器內(nèi)置在窗口中。
    2011-07-07

最新評(píng)論