首頁  >  文章  >  web前端  >  談談JS訊息機制和事件機制的理解_javascript技巧

談談JS訊息機制和事件機制的理解_javascript技巧

WBOY
WBOY原創
2016-05-16 15:05:381506瀏覽

訊息/事件機制幾乎是所有開發語言都有的機制,並不是deviceone的獨創,在某些語言稱之為訊息(Event),有些地方稱之為(Message). 其實原理是類似的,只不過有些實現的方式要複雜一點。我們deviceone統一就叫訊息.

訊息基礎概念

還有一些初學者不太熟悉這個機制,我們先簡單介紹一些基礎概念,如果熟悉的人可以跳過這個部分。
一個/條訊息可以理解為是一個資料結構,包含以下幾個基本部分:

1.消息來源:就是消息的來源,發出這個訊息的物件

2.訊息名:就是訊息的唯一標示

3.訊息數據:訊息發出後附帶的數據,有可能數據是空

訊息從種類上又可以分為2種:

1.系統訊息:由作業系統或deviceone系統發送出來的訊息,訊息的名稱是固定的。

2.自訂訊息:由開發者自己定義,自己發送出來的訊息,訊息的名字是隨意的,可以任意定義。

舉例說明:

例如使用者點擊一個do_Button按鈕,就會觸發一個系統訊息,包含3個部分:

1.訊息來源:使用者點中的button物件

2.訊息名:touch

3.訊息資料:這個訊息沒有附帶資料

例如使用者透過do_Button按鈕觸發一個自訂事件,包含3個部分:

1.訊息來源: button物件

2.訊息名稱:使用者隨便定義,叫aaa,bbb,ccc都可以

3.訊息資料:附帶的資料由觸發訊息的時候設定

發佈/訂閱模式

發布/訂閱模式是最常用的設計模式之一,是訊息機制的核心,其特點就是降低耦合度,讓二個獨立的物件不互相依賴。簡單介紹一下,熟悉的同學可以跳過。

我們先從現實的簡單例子來說明這個問題,參考下圖:


從這張圖我們可以看出

1.消費者和出版社互相不認識,消費者不需要了解他想要的雜誌是具體哪家出版社出的;出版社也不需要了解具體是哪個人定了他們出版社發行的書。

2.消費者和出版社必須都認識郵局。

3.消費者需要告訴郵局消費者的名字地址以及想要訂閱的雜誌名字

4.可以多個消費者訂閱同一本雜誌

5.郵局拿到雜誌後,會一一通知消費者,通知的時候同時把雜誌送到消費者手上。

看完上面現實例子,我們再來看抽象的描述會更清晰一點,看下圖:

和上面的實際例子描述一一對應:

1.系統/開發者和函數物件互相不依賴,系統/開發者只管觸發一個訊息,並不關心誰去接受

2.系統/開發者和函數物件必須能取得到訊息源物件

3.函數物件訂閱訊息的時候需要標示訊息的名稱和函數物件的參考

4.可以多個函數物件訂閱同一個訊息來源相同名字的訊息

5.訊息源觸發訊息會一一通知所有訂閱者,並把data資料傳遞到回呼函數物件

看完抽象的描述,我們最後來看實際的deviceone開發的例子,還是以do_Button為例子。

1. 當使用者點擊一個button,觸摸到的時候,系統會取得到button這個物件作為訊息來源,fire一個」touch」訊息,任何訂閱了」touch」訊息的函數物件都會接收到這個訊息並引起函數的執行。

//获取button对象
var btn_hello = ui("btn_hello");
//定义函数对象
function f(){
//当btn_hello这个按钮接收到手指点击就会执行下面的代码
deviceone.print("f 函数接收到点击触发消息")
}
function f(){
//当btn_hello这个按钮接收到手指点击就会执行下面的代码
deviceone.print("f 函数接收到点击触发消息")
}
//f,f订阅button的touch消息
btn_hello.on("touch",f);
btn_hello.on("touch",f);

2. 我們可以為button物件定義2個自訂的訊息”message1」和”message2”,分別有2個函數物件訂閱這2個訊息。但是最後要觸發這個訊息必須是開發者透過呼叫fire函數才能觸發,這就是和系統訊息的差別。

//获取button对象
var btn_hello = ui("btn_hello");
//定义函数对象
function f(d){
//当btn_hello这个按钮接收到开发者触发的消息message就会执行下面的代码
deviceone.print("f 函数接收到message消息,消息的数据是:"+d)
}
function f(d){
//当btn_hello这个按钮接收到开发者触发的消息message就会执行下面的代码
deviceone.print("f 函数接收到message消息,消息的数据是:"+d)
}
//f,f订阅button的touch消息
btn_hello.on("message",f);
btn_hello.on("message",f);
//触发消息
btn_hello.fire("message","data");
btn_hello.fire("message","data");

看到这里,你肯定会奇怪,为什么我们要在button上自定义对象?这有神马意义?其实确实没有意义也没有必要,这里只是拿button举例子,在常规的开发中,基本不会这么用。

消息的使用

前面讲了这么多,现在才是deviceone消息的使用。使用其实很简单,上面的例子基本说明的了系统事件和自定义事件的使用方法。

有几个概念再说明一下

1.deviceone的所有对象,包括UI,MM,SM对象都可以是消息源

// SM对象可以是消息源
var page = sm("do_Page");
page.on("loaded",function()){
// 这个是page对象的系统消息,这个消息不需要手动触发,系统会自动触发
}
page.on("message",function(d)){
// 这个是page对象的自定义消息
}
page.fire("message","data");
// MM对象可以是消息源
var http = mm("do_Http");
http.on("result",function()){
// 这个是http对象的系统消息,这个消息不需要手动触发,接受到http服务端的反馈后会自动触发
}
http.on("message",function(d)){
// 这个是http对象的自定义消息
}
http.fire("message","data");
//UI对象可以是消息源
var alayout = ui("alayout_id");
alayout.on("touch",function()){
// 这个是alayout对象的系统消息,这个消息不需要手动触发,手机点击就会触发
}
alayout.on("message",function(d)){
// 这个是alayout对象的自定义消息
}
alayout.fire("message","data");

2.消息源对象有作用域,所以订阅和触发的消息源必须是是一个作用域的同一个对象。这里结合数据分享和数据传递文档来理解。

看以下的例子,test1.ui和test2.ui有可能在一个page作用域,也有可能不在一个作业域,只有在一个作用域fire的消息才能正确送达回调函数。

判断是否一样,可以通过打印page的地址 page.getAddress().

//在test.ui.js里订阅消息
var page = sm("do_Page");
deviceone.print(page.getAddress());
page.on("message",function(d)){
deviceone.print(d);
}
//在test.ui.js触发消息
var page = sm("do_Page");
deviceone.print(page.getAddress());
page.fire("message","data");

如果不在同一page作用域,则可以把消息订阅在2个page都能共享到的app作用域
上面的代码改成:

//在test.ui.js里订阅消息
var app = sm("do_App");
app.on("message",function(d)){
deviceone.print(d);
}
//在test.ui.js触发消息
var app = sm("do_App");
app.fire("message","data");

3.同样的函数对象可以重复订阅一个对象源的消息,触发消息的时候会使函数执行多次,这是初学者经常犯的错误。

var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("执行次数"+(count++));
}
page.on("message",f);
page.on("message",f);
page.fire("message");

看上面的例子,如果执行的话,会打印2此,因为订阅了2次,或许你会说谁会写这样的代码?实际情况肯定没有这么容易看出来执行了重复的on函数,实际情况经常是比如在点击事件里执行on函数,每点击一下按钮,就重复订阅一次。

4.消息的订阅一定要在消息的触发之前,这是初学者经常犯的错误。

var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("执行次数"+(count++));
}
page.fire("message");
page.on("message",f);

看上面的例子,如果执行的话,会没有效果,或许你会说谁会写这样的代码?实际情况肯定没有这么容易看出来顺序反了,实际情况经常是比如on函数执行在某一个函数的回调函数里,你无法确定回调函数啥时候执行,是否是在fire之前执行。一般碰到这种情况可以加几个deviceone.print打印一下看看是on先执行还是fire先执行。

5.有订阅就有取消订阅,取消订阅是off函数,之所以很少用,是因为closePage的时候会自动把当前page作用域订阅的消息全部释放。

但是如果消息订阅在app作用域,就要注意,可能需要手动去取消订阅。否则就会出现触发消息的时候会使函数执行多次的问题。

var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("执行次数"+(count++));
}
page.on("message",f);
page.fire("message");
.page.off("message");
page.fire("message");

看上面的例子,打印只会执行一次,因为fire一次后就取消订阅了。

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