基于事件的Web應(yīng)用
傳統(tǒng)的Web表單提交就是典型的基于事件的模式。換句話說(shuō),在Web表單里輸入了很多數(shù)據(jù)(用戶輸入文本框,點(diǎn)選復(fù)選框,從列表中選中某些項(xiàng)等等),之后這些數(shù)據(jù)提交給服務(wù)器。這個(gè)場(chǎng)景中實(shí)際是一個(gè)單一的程序事件:使用POST方式將表單數(shù)據(jù)提交。這也是基于Ajax的Web應(yīng)用的工作原理。
一次性發(fā)送大量數(shù)據(jù)
對(duì)于Ajax來(lái)說(shuō),是可以和基于事件編程扯上一點(diǎn)關(guān)系。客戶端和服務(wù)器端之間有些交互可以認(rèn)為是基于事件的。典型的場(chǎng)景是輸入一個(gè)省市代碼,發(fā)送請(qǐng)求到服務(wù)器獲得城市和省的名稱。這里通過(guò)XmlHttpRequest的Ajax并不需要將很多數(shù)據(jù)一次性扔給服務(wù)器。但這并不能改變大部分web應(yīng)用都是基于頁(yè)面刷新這種模式的現(xiàn)狀。Ajax已經(jīng)更廣泛的用于很多有意思的視覺(jué)相關(guān)的交互,快速的作表單驗(yàn)證,無(wú)刷新提交數(shù)據(jù),這樣就可以避免重新載入頁(yè)面。因此,盡管并未通過(guò)提交表單來(lái)發(fā)起一個(gè)真正的POST請(qǐng)求,通過(guò)Ajax可以模擬POST表單提交。
坦率的講,這種傳統(tǒng)的Ajax交互方式也阻礙了Ajax程序員的創(chuàng)新。每次發(fā)送一個(gè)請(qǐng)求時(shí)(不管請(qǐng)求的數(shù)據(jù)多么。,都會(huì)在網(wǎng)絡(luò)里走一個(gè)來(lái)回。服務(wù)器必須針對(duì)這個(gè)請(qǐng)求作出響應(yīng),通常是開(kāi)辟一個(gè)新的進(jìn)程。因此,如果你真正置身于一個(gè)事件模型的環(huán)境中作開(kāi)發(fā),你可能需要通過(guò)發(fā)起10到15個(gè)單獨(dú)的小請(qǐng)求來(lái)保持你的頁(yè)面和服務(wù)器之間的聯(lián)系,服務(wù)器也會(huì)為之創(chuàng)建10到15個(gè)線程(可能更少,這取決于服務(wù)器處理新請(qǐng)求時(shí)分配線程池的策略),當(dāng)這個(gè)數(shù)量乘以1000或者10000或者100000時(shí)(譯注:每個(gè)頁(yè)面需要10個(gè)請(qǐng)求,那么越多用戶訪問(wèn)這個(gè)頁(yè)面,所發(fā)起的請(qǐng)求個(gè)數(shù)就會(huì)越來(lái)越多),就會(huì)出現(xiàn)內(nèi)存溢出、邏輯交錯(cuò)帶來(lái)的沖突、網(wǎng)絡(luò)癱瘓、系統(tǒng)崩潰這些問(wèn)題。
結(jié)果是,在大多數(shù)場(chǎng)景中,Web應(yīng)用需要保持對(duì)事件的最小依賴。有一個(gè)折衷方案,就是服務(wù)器端程序的響應(yīng)返回的不是一個(gè)微小的數(shù)據(jù)片段,而是帶有更多冗余數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)包,通常是JSON數(shù)據(jù),這時(shí)就又遇到了eval()的問(wèn)題。問(wèn)題當(dāng)然出在eval()身上,但這也和Web本身和服務(wù)器線程控制、包括頁(yè)面和服務(wù)器之間的HTTP請(qǐng)求和響應(yīng)策略(至少在這個(gè)場(chǎng)景下)有密不可分的關(guān)系。
或許有些人對(duì)上文提到的問(wèn)題不以為然,因?yàn)槟阒烙泻芏喾椒▉?lái)規(guī)避直接eval()帶來(lái)的問(wèn)題,你會(huì)使用諸如JSON.parse()來(lái)代替eval()。同樣有很多令人信服的論據(jù)鼓勵(lì)我們小心的使用eval()。這些東東都是值得進(jìn)一步討論的。但不管怎樣,看一看eval()帶來(lái)了太多類似棧溢出(Stack Overflow)這類的問(wèn)題吧,你會(huì)發(fā)現(xiàn)大部分程序員并未正確或者安全的使用eval()。這著實(shí)是一個(gè)問(wèn)題。因?yàn)樘嗖锁B(niǎo)程序員似乎根本沒(méi)有意識(shí)到eval()的問(wèn)題有多嚴(yán)重。
不斷的發(fā)送少量的數(shù)據(jù)
Node帶來(lái)了架構(gòu)應(yīng)用的新思路,我們可以基于Node采用事件模型來(lái)架構(gòu)Web應(yīng)用,或者說(shuō)“小型的”事件模型。換句話說(shuō),你應(yīng)當(dāng)基于大量的事件發(fā)送大量的請(qǐng)求,每個(gè)請(qǐng)求的數(shù)據(jù)包都很小,或者根據(jù)需要從后臺(tái)抓取少量數(shù)據(jù),而不是發(fā)送很少的請(qǐng)求,每次請(qǐng)求都帶有大量的數(shù)據(jù)。在很多場(chǎng)景中,大多數(shù)情況下你需要喚醒GUI程序(Java Swing程序員的GUI知識(shí)儲(chǔ)備可以派上用場(chǎng)了)。因此,當(dāng)用戶輸入姓氏和名字后,移步到下一個(gè)輸入框,這時(shí)就已經(jīng)發(fā)起了一個(gè)請(qǐng)求來(lái)驗(yàn)證輸入的用戶名是否已經(jīng)存在。省市代碼、地址和電話號(hào)碼的驗(yàn)證也是同理。頁(yè)面上每發(fā)生一個(gè)時(shí)間,都會(huì)產(chǎn)生一個(gè)請(qǐng)求和響應(yīng)。
這有什么不同嗎?為什么Node可以做到,并規(guī)避了已有的線程問(wèn)題?其實(shí)Node并沒(méi)有這么神秘,Node官網(wǎng)充分解釋了其哲學(xué):
Node的目標(biāo)是提供一種構(gòu)建可伸縮的網(wǎng)絡(luò)應(yīng)用的方案,在hello world例子中,服務(wù)器可以同時(shí)處理很多客戶端連接。Node和操作系統(tǒng)有一種約定,如果創(chuàng)建了新的鏈接,操作系統(tǒng)就將通知Node,然后進(jìn)入休眠。如果有人創(chuàng)建了新的鏈接,那么它(Node)執(zhí)行一個(gè)回調(diào),每一個(gè)鏈接只占用了非常小的(內(nèi)存)堆棧開(kāi)銷。
Node是無(wú)阻塞的,不會(huì)出現(xiàn)同源競(jìng)爭(zhēng)線程的情況(Node非常樂(lè)于處理即時(shí)的請(qǐng)求,發(fā)生了什么事情,那就讓他發(fā)生吧),新請(qǐng)求到達(dá)服務(wù)器時(shí),不需要為這個(gè)請(qǐng)求單獨(dú)作什么事情。Node僅僅是悠閑的坐在那里等待(請(qǐng)求的發(fā)生),有請(qǐng)求就處理請(qǐng)求。用非常簡(jiǎn)單的代碼就可以實(shí)現(xiàn),而不用花費(fèi)程序員寶貴的精力去實(shí)現(xiàn)一整套服務(wù)器端邏輯。
沒(méi)錯(cuò),混亂不可避免
值得一提的是,非阻塞系統(tǒng)帶來(lái)的問(wèn)題也會(huì)出現(xiàn)在這種編程模式中:一個(gè)進(jìn)程(非線程)等待一個(gè)數(shù)據(jù)存儲(chǔ)操作,這時(shí)產(chǎn)生了另外一個(gè)抓取與之無(wú)關(guān)的數(shù)據(jù)的操作,這個(gè)意外的操作會(huì)對(duì)現(xiàn)有的等待造成影響(譯注:作者的意思是說(shuō)多個(gè)操作同時(shí)發(fā)生或者沒(méi)有按照預(yù)定順序發(fā)生時(shí),會(huì)產(chǎn)生混亂,也就是說(shuō),操作本身并不是原子性的)。但要注意,大多數(shù)基于事件的web編程模式都是“只讀的”!你大概也沒(méi)有遇到過(guò)通過(guò)“微請(qǐng)求”來(lái)修改數(shù)據(jù)的情況,或者說(shuō)非常罕見(jiàn)。相反,通過(guò)這種請(qǐng)求來(lái)驗(yàn)證數(shù)據(jù)合法性、查詢數(shù)據(jù)的情形則非常常見(jiàn)。這種情況下,最好直接根據(jù)請(qǐng)求作響應(yīng)。數(shù)據(jù)庫(kù)本身會(huì)作加鎖操作,一般來(lái)講,一個(gè)優(yōu)秀的數(shù)據(jù)庫(kù)完全可以高效的做到數(shù)據(jù)操作的加鎖解鎖,而不用服務(wù)器端的程序代碼去多做什么。而Node又比操作系統(tǒng)處理線程的保持和釋放更加高效,使得服務(wù)器不必單獨(dú)為“web響應(yīng)”開(kāi)辟一個(gè)進(jìn)程。
此外,Node也計(jì)劃實(shí)現(xiàn)“進(jìn)程分支”(process forking),HTML5 Web Workers API為更復(fù)雜的進(jìn)程控制提供了引擎(規(guī)范)支持。同樣,如果你采用基于事件的模型來(lái)架構(gòu)web應(yīng)用,你的程序可能至少有100多個(gè)場(chǎng)景需要線程的支持。最終你會(huì)發(fā)現(xiàn),你的編程思路和思考問(wèn)題的方式發(fā)生了改變,你的注意力將放在服務(wù)器端處理請(qǐng)求的邏輯上,而不必在乎Node如何工作。
出處:Taobao.com UED Team
責(zé)任編輯:bluehearts
上一頁(yè) 什么是Node? [7] 下一頁(yè) 什么是Node? [8]
◎進(jìn)入論壇網(wǎng)頁(yè)制作、WEB標(biāo)準(zhǔn)化版塊參加討論,我還想發(fā)表評(píng)論。
|