談一談JS消息機(jī)制和事件機(jī)制的理解
消息/事件機(jī)制是幾乎所有開(kāi)發(fā)語(yǔ)言都有的機(jī)制,并不是deviceone的獨(dú)創(chuàng),在某些語(yǔ)言稱之為消息(Event),有些地方稱之為(Message). 其實(shí)原理是類似的,只不過(guò)有些實(shí)現(xiàn)的方式要復(fù)雜一點(diǎn)。我們deviceone統(tǒng)一就叫消息.
消息基礎(chǔ)概念
還有一些初學(xué)者不太熟悉這個(gè)機(jī)制,我們先簡(jiǎn)單介紹一些基礎(chǔ)概念,如果熟悉的人可以跳過(guò)這個(gè)部分。
一個(gè)/條消息可以理解為是一個(gè)數(shù)據(jù)結(jié)構(gòu),包含以下幾個(gè)基本部分:
1.消息源:就是消息的來(lái)源,發(fā)出這個(gè)消息的對(duì)象
2.消息名:就是消息的唯一標(biāo)示
3.消息數(shù)據(jù):消息發(fā)出后附帶的數(shù)據(jù),有可能數(shù)據(jù)是空
消息從種類上又可以分為2種:
1.系統(tǒng)消息:由操作系統(tǒng)或deviceone系統(tǒng)發(fā)送出來(lái)的消息,消息的名稱是固定的。
2.自定義消息:由開(kāi)發(fā)者自己定義,自己發(fā)送出來(lái)的消息,消息的名字是隨意的,可以任意定義。
舉例說(shuō)明:
比如用戶點(diǎn)擊一個(gè)do_Button按鈕,就會(huì)觸發(fā)一個(gè)系統(tǒng)消息,包含3個(gè)部分:
1.消息源:用戶點(diǎn)中的button對(duì)象
2.消息名:touch
3.消息數(shù)據(jù):這個(gè)消息沒(méi)有附帶數(shù)據(jù)
比如用戶通過(guò)do_Button按鈕觸發(fā)一個(gè)自定義事件,包含3個(gè)部分:
1.消息源: button對(duì)象
2.消息名:用戶隨便定義,叫aaa,bbb,ccc都可以
3.消息數(shù)據(jù):附帶的數(shù)據(jù)由觸發(fā)消息的時(shí)候設(shè)定
發(fā)布/訂閱模式
發(fā)布/訂閱模式是最常用的設(shè)計(jì)模式之一,是消息機(jī)制的核心,其特點(diǎn)就是降低耦合度,讓二個(gè)獨(dú)立的對(duì)象不互相依賴。簡(jiǎn)單介紹一下,熟悉的同學(xué)可以跳過(guò)。
我們先從現(xiàn)實(shí)的一個(gè)簡(jiǎn)單例子來(lái)說(shuō)明這個(gè)問(wèn)題,參考下圖:

從這個(gè)圖我們可以看出
1.消費(fèi)者和出版社互相不認(rèn)識(shí),消費(fèi)者不需要了解他想要的雜志是具體哪家出版社出的;出版社也不需要了解具體是哪個(gè)人定了他們出版社發(fā)行的書(shū)。
2.消費(fèi)者和出版社必須都認(rèn)識(shí)郵局。
3.消費(fèi)者需要告訴郵局消費(fèi)者的名字地址以及想要訂閱的雜志名字
4.可以多個(gè)消費(fèi)者訂閱同一本雜志
5.郵局拿到雜志后,會(huì)一一通知消費(fèi)者,通知的時(shí)候同時(shí)把雜志送到消費(fèi)者手里。
看完上面現(xiàn)實(shí)例子,我們?cè)賮?lái)看抽象的描述會(huì)更清晰一點(diǎn),看下圖:

和上面的實(shí)際例子描述一一對(duì)應(yīng):
1.系統(tǒng)/開(kāi)發(fā)者和函數(shù)對(duì)象互相不依賴,系統(tǒng)/開(kāi)發(fā)者只管觸發(fā)一個(gè)消息,并不關(guān)心誰(shuí)去接受
2.系統(tǒng)/開(kāi)發(fā)者和函數(shù)對(duì)象必須能獲取到消息源對(duì)象
3.函數(shù)對(duì)象訂閱消息的時(shí)候需要標(biāo)示消息的名稱和函數(shù)對(duì)象的引用
4.可以多個(gè)函數(shù)對(duì)象訂閱同一個(gè)消息源同一名字的消息
5.消息源觸發(fā)消息會(huì)一一通知所有訂閱者,并把data數(shù)據(jù)傳遞到回調(diào)函數(shù)對(duì)象
看完抽象的描述,我們最后來(lái)看實(shí)際的deviceone開(kāi)發(fā)的例子,還是以do_Button為例子。
1. 當(dāng)用戶點(diǎn)擊一個(gè)button,觸摸到的時(shí)候,系統(tǒng)會(huì)獲取到button這個(gè)對(duì)象作為消息源,fire一個(gè)”touch”消息,任何訂閱了”touch”消息的函數(shù)對(duì)象都會(huì)接收到這個(gè)消息并引起函數(shù)的執(zhí)行。
//獲取button對(duì)象
var btn_hello = ui("btn_hello");
//定義函數(shù)對(duì)象
function f(){
//當(dāng)btn_hello這個(gè)按鈕接收到手指點(diǎn)擊就會(huì)執(zhí)行下面的代碼
deviceone.print("f 函數(shù)接收到點(diǎn)擊觸發(fā)消息")
}
function f(){
//當(dāng)btn_hello這個(gè)按鈕接收到手指點(diǎn)擊就會(huì)執(zhí)行下面的代碼
deviceone.print("f 函數(shù)接收到點(diǎn)擊觸發(fā)消息")
}
//f,f訂閱button的touch消息
btn_hello.on("touch",f);
btn_hello.on("touch",f);
2. 我們可以為button對(duì)象定義2個(gè)自定義的消息”message1”和”message2”,分別有2個(gè)函數(shù)對(duì)象訂閱這2個(gè)消息。但是最后要觸發(fā)這個(gè)消息必須是開(kāi)發(fā)者通過(guò)調(diào)用fire函數(shù)才能觸發(fā),這就是和系統(tǒng)消息的區(qū)別。
//獲取button對(duì)象
var btn_hello = ui("btn_hello");
//定義函數(shù)對(duì)象
function f(d){
//當(dāng)btn_hello這個(gè)按鈕接收到開(kāi)發(fā)者觸發(fā)的消息message就會(huì)執(zhí)行下面的代碼
deviceone.print("f 函數(shù)接收到message消息,消息的數(shù)據(jù)是:"+d)
}
function f(d){
//當(dāng)btn_hello這個(gè)按鈕接收到開(kāi)發(fā)者觸發(fā)的消息message就會(huì)執(zhí)行下面的代碼
deviceone.print("f 函數(shù)接收到message消息,消息的數(shù)據(jù)是:"+d)
}
//f,f訂閱button的touch消息
btn_hello.on("message",f);
btn_hello.on("message",f);
//觸發(fā)消息
btn_hello.fire("message","data");
btn_hello.fire("message","data");
看到這里,你肯定會(huì)奇怪,為什么我們要在button上自定義對(duì)象?這有神馬意義?其實(shí)確實(shí)沒(méi)有意義也沒(méi)有必要,這里只是拿button舉例子,在常規(guī)的開(kāi)發(fā)中,基本不會(huì)這么用。
消息的使用
前面講了這么多,現(xiàn)在才是deviceone消息的使用。使用其實(shí)很簡(jiǎn)單,上面的例子基本說(shuō)明的了系統(tǒng)事件和自定義事件的使用方法。
有幾個(gè)概念再說(shuō)明一下
1.deviceone的所有對(duì)象,包括UI,MM,SM對(duì)象都可以是消息源
// SM對(duì)象可以是消息源
var page = sm("do_Page");
page.on("loaded",function()){
// 這個(gè)是page對(duì)象的系統(tǒng)消息,這個(gè)消息不需要手動(dòng)觸發(fā),系統(tǒng)會(huì)自動(dòng)觸發(fā)
}
page.on("message",function(d)){
// 這個(gè)是page對(duì)象的自定義消息
}
page.fire("message","data");
// MM對(duì)象可以是消息源
var http = mm("do_Http");
http.on("result",function()){
// 這個(gè)是http對(duì)象的系統(tǒng)消息,這個(gè)消息不需要手動(dòng)觸發(fā),接受到http服務(wù)端的反饋后會(huì)自動(dòng)觸發(fā)
}
http.on("message",function(d)){
// 這個(gè)是http對(duì)象的自定義消息
}
http.fire("message","data");
//UI對(duì)象可以是消息源
var alayout = ui("alayout_id");
alayout.on("touch",function()){
// 這個(gè)是alayout對(duì)象的系統(tǒng)消息,這個(gè)消息不需要手動(dòng)觸發(fā),手機(jī)點(diǎn)擊就會(huì)觸發(fā)
}
alayout.on("message",function(d)){
// 這個(gè)是alayout對(duì)象的自定義消息
}
alayout.fire("message","data");
2.消息源對(duì)象有作用域,所以訂閱和觸發(fā)的消息源必須是是一個(gè)作用域的同一個(gè)對(duì)象。這里結(jié)合數(shù)據(jù)分享和數(shù)據(jù)傳遞文檔來(lái)理解。
看以下的例子,test1.ui和test2.ui有可能在一個(gè)page作用域,也有可能不在一個(gè)作業(yè)域,只有在一個(gè)作用域fire的消息才能正確送達(dá)回調(diào)函數(shù)。
判斷是否一樣,可以通過(guò)打印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觸發(fā)消息
var page = sm("do_Page");
deviceone.print(page.getAddress());
page.fire("message","data");
如果不在同一page作用域,則可以把消息訂閱在2個(gè)page都能共享到的app作用域
上面的代碼改成:
//在test.ui.js里訂閱消息
var app = sm("do_App");
app.on("message",function(d)){
deviceone.print(d);
}
//在test.ui.js觸發(fā)消息
var app = sm("do_App");
app.fire("message","data");
3.同樣的函數(shù)對(duì)象可以重復(fù)訂閱一個(gè)對(duì)象源的消息,觸發(fā)消息的時(shí)候會(huì)使函數(shù)執(zhí)行多次,這是初學(xué)者經(jīng)常犯的錯(cuò)誤。
var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("執(zhí)行次數(shù)"+(count++));
}
page.on("message",f);
page.on("message",f);
page.fire("message");
看上面的例子,如果執(zhí)行的話,會(huì)打印2此,因?yàn)橛嗛喠?次,或許你會(huì)說(shuō)誰(shuí)會(huì)寫(xiě)這樣的代碼?實(shí)際情況肯定沒(méi)有這么容易看出來(lái)執(zhí)行了重復(fù)的on函數(shù),實(shí)際情況經(jīng)常是比如在點(diǎn)擊事件里執(zhí)行on函數(shù),每點(diǎn)擊一下按鈕,就重復(fù)訂閱一次。
4.消息的訂閱一定要在消息的觸發(fā)之前,這是初學(xué)者經(jīng)常犯的錯(cuò)誤。
var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("執(zhí)行次數(shù)"+(count++));
}
page.fire("message");
page.on("message",f);
看上面的例子,如果執(zhí)行的話,會(huì)沒(méi)有效果,或許你會(huì)說(shuō)誰(shuí)會(huì)寫(xiě)這樣的代碼?實(shí)際情況肯定沒(méi)有這么容易看出來(lái)順序反了,實(shí)際情況經(jīng)常是比如on函數(shù)執(zhí)行在某一個(gè)函數(shù)的回調(diào)函數(shù)里,你無(wú)法確定回調(diào)函數(shù)啥時(shí)候執(zhí)行,是否是在fire之前執(zhí)行。一般碰到這種情況可以加幾個(gè)deviceone.print打印一下看看是on先執(zhí)行還是fire先執(zhí)行。
5.有訂閱就有取消訂閱,取消訂閱是off函數(shù),之所以很少用,是因?yàn)閏losePage的時(shí)候會(huì)自動(dòng)把當(dāng)前page作用域訂閱的消息全部釋放。
但是如果消息訂閱在app作用域,就要注意,可能需要手動(dòng)去取消訂閱。否則就會(huì)出現(xiàn)觸發(fā)消息的時(shí)候會(huì)使函數(shù)執(zhí)行多次的問(wèn)題。
var page = sm("do_Page");
var count = ;
function f(){
deviceone.print("執(zhí)行次數(shù)"+(count++));
}
page.on("message",f);
page.fire("message");
.page.off("message");
page.fire("message");
看上面的例子,打印只會(huì)執(zhí)行一次,因?yàn)閒ire一次后就取消訂閱了。
相關(guān)文章
Javascript 強(qiáng)制類型轉(zhuǎn)換函數(shù)
javascript是弱類型的語(yǔ)言,所以強(qiáng)制類型轉(zhuǎn)換還是比較重要的,下面看一下它的幾個(gè)強(qiáng)制轉(zhuǎn)換的函數(shù)2009-05-05
使用JavaScript實(shí)現(xiàn)二值化圖像
這篇文章主要為大家詳細(xì)介紹了使用JavaScript將圖像轉(zhuǎn)換為黑白二值圖的兩種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
Js實(shí)現(xiàn)當(dāng)前點(diǎn)擊a標(biāo)簽變色突出顯示其他a標(biāo)簽回復(fù)原色
當(dāng)一個(gè)頁(yè)面有多個(gè)a標(biāo)簽,實(shí)現(xiàn)當(dāng)前點(diǎn)擊a標(biāo)簽變色,其他a標(biāo)簽回復(fù)原色,具體實(shí)現(xiàn)如下,喜歡的朋友可以參考下2013-11-11
js實(shí)現(xiàn)根據(jù)文件url批量壓縮下載成zip包
本文主要介紹了js實(shí)現(xiàn)根據(jù)文件url批量壓縮下載成zip包,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
JavaScript SHA512&SHA256加密算法詳解
本文給大家分享的是javascript版的SHA512&SHA256加密算法的代碼,以及用法,有需要的小伙伴可以參考下。2015-08-08
JS實(shí)現(xiàn)點(diǎn)擊鏈接切換顯示隱藏內(nèi)容的方法
這篇文章主要介紹了JS實(shí)現(xiàn)點(diǎn)擊鏈接切換顯示隱藏內(nèi)容的方法,涉及javascript鼠標(biāo)事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)變換相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
layui導(dǎo)航欄二級(jí)菜單不顯示問(wèn)題及解決
這篇文章主要介紹了layui導(dǎo)航欄二級(jí)菜單不顯示問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
通過(guò)網(wǎng)頁(yè)查看JS源碼中漢字顯示亂碼的解決方法
這篇文章給大家主要介紹了通過(guò)網(wǎng)頁(yè)查看JS源碼的時(shí)候,發(fā)現(xiàn)漢字顯示是亂碼的解決方法,文中通過(guò)圖文詳解的介紹了解決的步驟,詳細(xì)會(huì)對(duì)大家很有幫助,有需要的朋友們下面來(lái)一起看看吧。2016-10-10

