前端框架以及node各種深入淺出_第1頁
前端框架以及node各種深入淺出_第2頁
前端框架以及node各種深入淺出_第3頁
前端框架以及node各種深入淺出_第4頁
前端框架以及node各種深入淺出_第5頁
免費(fèi)預(yù)覽已結(jié)束,剩余26頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、深入淺出 Node.js不Node.js不是JS應(yīng)用深入淺出 Node.js不Node.js不是JS應(yīng)用、而是JS運(yùn) C+語言編寫而成,是一個(gè) Javascript 的運(yùn)行環(huán)境。為什么采用 C+語言呢?據(jù) Node.js 創(chuàng)始Ryan Dahl 回憶,他最初來寫 Node.js,但是后來發(fā)現(xiàn) Ruby 虛擬機(jī)的性能不足他的要求,后來他嘗試采用 V8 引擎,所以選擇了 C+語言。既然不是 Javascript 應(yīng)用,為何叫.js 呢?因?yàn)?Node.js 是一個(gè) Javascript 的運(yùn)行環(huán)境。提到 Javascript,大家首先想到的是日常 引擎負(fù)責(zé)解釋執(zhí)行網(wǎng)頁中的 Javascript 代

2、碼。作為 Web 前端最重要的語言之一,Javascript 一直 Node.js Chrome 瀏覽器的 V8 引擎,性能很好,同時(shí)還提供了很多系統(tǒng)級的 Node.js 采用事件驅(qū)動(dòng)、異步編程,為網(wǎng)絡(luò)服務(wù)而設(shè) 可以在此基礎(chǔ)上快速構(gòu)建Web 可以在此基礎(chǔ)上快速構(gòu)建Web 值為 Node.js 的網(wǎng)絡(luò)編程比較便利,提供的模塊(在這里是 http)開放了容易上手的 API 接 制Node.js 不是內(nèi)存(還記得JavaOutOfMemory異常的日子嗎?)var http = require(http); http.createServer(function(req,res)res.writeHe

3、ad(200,Content-Type:text/plain); o Worldn);).listen(80, (30M (30M程、單線程模式,那么在如今多核硬件流行的環(huán)境中,單核性能出色的 Node.js 如何利用多核 多采用Node.js varhostRequest= var responseHTML =; response.on(data, function (cresponseHTML=responseHTML+/dosomething 。 的開 服 站 3Sinatra3 站 3Sinatra3 MyFOX 榨干 CPU。例如,頻繁地打開和關(guān)閉連接會讓大量端口處于等待狀態(tài),當(dāng)并發(fā)

4、數(shù)量上去之后, Node.jsNode.js&NPM 的安裝Node.js 安裝與配 到在過去,Node.js 一直不支持在下原生編譯需要借助Cygwin 或MinGW 來模才能編譯安裝。幸運(yùn)的2011 6 月微軟開始與Joyent 合作移植Node.js 上 布上。這次的版本發(fā)布使得Node.js 在全擺脫掉Cygwin或MinGW式的環(huán)境,并且在某些細(xì)節(jié)方面節(jié)參見在 下,我將介紹二種安裝 Node.js 的方法,即在 下,我將介紹二種安裝 Node.js 的方法,即到Node.js 編譯好的msi 文件。然后雙該引導(dǎo)步驟會將node.exe 文件安裝到 C:Program Files 添加

5、PATH ,但是卻用gyp 工具上,Node.js采用gyp來生成Visual Studio Solution文件,最終通過VC+的編譯+ HYPERLINK http:/m/en-us/vstudio/hh388567 ,執(zhí)行 vcbuild.bat release 命令,然后經(jīng)歷了漫長的等待后,編譯完成在下可以找到編譯好的node.exe 文件。通過命令行執(zhí)行node -v 命令,你將會在下找到node.msinode-由于Node.js 尚處于v0.x.x 版都不會預(yù)置Node 的二進(jìn)制用 由于Node.js 尚處于v0.x.x 版都不會預(yù)置Node 的二進(jìn)制用 安裝如同在 下一樣,No

6、de.js 依然是采用gyp 工具管理生成項(xiàng)目的,不make 工具行最終的編譯。所以。用gyp,可以通過在命令,查看是否已安 Debian/Ubuntu下的工具是apt-get RedHat/centOS 下通過yum 命令libssl-devapt-get install libssl-dev 等命令檢查環(huán)境并tarzxvfnode-v0.6.1.tar.gz cd node-v0.6.1上面幾行命令是通過wget 命令版本的代碼,并解壓之。./configure 命令將會檢查環(huán)境是否符合NodejsCheckingforprogramg+orc+:/usr/bin/g+ Checking

7、for program cpp : /usr/bin/cpp Checking for program ar : /usr/bin/ar Checking for program ranlib : /usr/bin/ranlib Checking f+ : okCheckingforprogramgccorcc:/usr/bin/gcc Checking for program ar : /usr/bin/ar Checkingforprogramranlib:/usr/bin/ranlibScala,讓上的編程重現(xiàn)生相關(guān)廠商如果檢查沒有通過,請確認(rèn)上面提到的三個(gè)條件是否滿足。如果 confi

8、gure 命令執(zhí)行成功,就可Nodejs 通過make 工具進(jìn)行編譯和安裝(如果make install 不成功,請使用sudo如果檢查沒有通過,請確認(rèn)上面提到的三個(gè)條件是否滿足。如果 configure 命令執(zhí)行成功,就可Nodejs 通過make 工具進(jìn)行編譯和安裝(如果make install 不成功,請使用sudo 以確保至此,Nodejs已經(jīng)編譯并安裝完成。如需卸載,可以執(zhí)行makeuninstall進(jìn)行以上介紹了*nix 下Nodejs 的安裝,之后可以如同 你就可以通過瀏覽nodevar http = require(http); http.createServer(functi

9、on(req,res)res.writeHead(200,Content-Type:text/plain); o Worldn);).listen(1337, console.log(Server running node-makeChecking fcc : ok Checkingforlibrarydl:yes Checking for openssl : yesCheckingforlibraryutil:yes Checking for library rt : yesChecking for fdatasync(2) with c+ : yes configure finished

10、sucsfully(7.350s)安裝NPM 的全稱是Node Package Manager,如果你熟悉ruby 的PyPL、的pear,那么你就知道NPM的作用是什么了。安裝NPM 的全稱是Node Package Manager,如果你熟悉ruby 的PyPL、的pear,那么你就知道NPM的作用是什么了。沒錯(cuò),它就是Nodejs的包管理器。Nodejs自身提供了基本的5112個(gè)Nodejs庫或框架,這些庫從各個(gè)方面可以幫助Nodejs的開發(fā)者完成較為復(fù)雜安裝庫,以及在大陸的網(wǎng)絡(luò)環(huán)境下,如何更好的利用NPM就像)上介紹的那樣,安裝,按后通過管道符| 將獲取交由sh 命令來執(zhí)行。這里如果限

11、會安裝不成功,需要加上sudo安裝成功后執(zhí)行npm 命令,會得到一下的以underscore 為例,來展示下通過npm 安裝 HYPERLINK mailto:underscore1.2.2 underscore1.2.2 npmUsage: npm where isoneof:adduser,apihelp,author,bin,bugs,c,cache,completion, config, deprecate, docs, edit, explore, faq, find, get, help,help-search,home,i,info,init,install,la,link, l

12、ist, ll, ln, ls, outdated, owner, pack, prefix, prune, publish, r, rb, rebuild, remove, restart, rm, root,run-script,s,se,search,set,show,star,start,stop, submodule, tag, test, un, uninstall, unlink, unpublish, unstar, up, update, ver, view, whoami|sudo|由于一些特殊的網(wǎng)絡(luò)環(huán)境,直接通過npminstall命令安裝的是國內(nèi) CNode 社區(qū)的fi

13、re9 同學(xué)利用空余時(shí)間搭建了一個(gè)鏡像的由于一些特殊的網(wǎng)絡(luò)環(huán)境,直接通過npminstall命令安裝的是國內(nèi) CNode 社區(qū)的fire9 同學(xué)利用空余時(shí)間搭建了一個(gè)鏡像的庫npmconfigsetregistry HYPERLINK http:/n/ 由于Nodejs 最初在Linux 開發(fā)下的歷史原因,導(dǎo)致NPM 一開始也不支持Windows 環(huán)境,但,NPMWindows下的需求亦是日漸增加。下面開Windows下的NPM安裝 GIT 不支持直打包了所有submodule的源碼包,所以需要通過git工具來簽出所有的由于碼。從msysgit 這個(gè)下的版本文件為Git-preview2011

14、1027.exe)。NPM 打開命令行工(CMD) msysgit 簽出NPM 的所有源碼和依賴代碼并安裝npm在執(zhí)行這段代碼之前,請確保node.exe 是跟通過node.msi 的方式安裝的,或者在PATH 環(huán)境變量中。段命令也會將npm加入到PATH 環(huán)境變量中去,之后可以隨處執(zhí)行npm命令。如果安裝中遇到權(quán)的錯(cuò)誤,請確保 HYPERLINK mailto:underscore1.2.2 underscore1.2.2 npmgit clone -recursivecd npmnodecli.jsinstallnpm-npm-registry HYPERLINK http:/n/ /下的

15、NPM安裝完畢。如果遭遇網(wǎng)絡(luò)問題無法安裝,請參照Linux下的NPM命令下的NPM安裝完畢。如果遭遇網(wǎng)絡(luò)問題無法安裝,請參照Linux下的NPM命令,深入Node.js 的模塊機(jī)Node.js 模塊的實(shí)之前在網(wǎng)上查閱了許多介紹Node.js 的文章,可惜對于 Node.js 的模塊機(jī)制大都著墨不多。在后續(xù)介紹模塊的使用之前我認(rèn)為有必要深入一下Node.js 的模塊機(jī)制早在后,JavaScript 就一直在探索本地編程的路,Rhino 是其代表產(chǎn)物。無奈那時(shí)服務(wù)端 誕走的路均是參考眾多服務(wù)器端語言來實(shí)現(xiàn)的,在這樣的背景之下,一沒有特色,二沒有實(shí)用價(jià)值。但是隨著 端的應(yīng)用越來越廣泛,以及服務(wù)端 J

16、avaScript 的推動(dòng),JavaScript 現(xiàn)有的規(guī)范十分薄弱,不利于 JavaScript 大規(guī)的應(yīng)用。那些以 JavaScript 為宿主語言的環(huán)境中,只有本身的基礎(chǔ)原生對象和類型的對象和 API 可以看到 JavaScript 缺少這些功能提供,所以JavaScript 庫外,沒有文件系統(tǒng)的 APIIO 流API JavaScript 沒有標(biāo)準(zhǔn)接口。沒有如Web Server JavaScript 于是便有了)規(guī)范的出現(xiàn),其目標(biāo)是為了構(gòu)建JavaScript 在包括 Web 服務(wù)器CommoJS制定了解決這些問題的一些而Nod.s就是這些規(guī)范的一種實(shí)現(xiàn)。Nod.s自身實(shí)現(xiàn)了rqir

17、e方法作為其引入模塊的方法,同時(shí)NPM基于CommoJS定義的包規(guī)范,實(shí)現(xiàn)了依賴管理和模塊自動(dòng)安裝等功能。這里將深入一下Node.js 的require 機(jī)制和NPM 基于包規(guī)范的應(yīng)用在Node.js 式以計(jì)算圓形的面積和周長兩個(gè)方法為例,來表現(xiàn) Node.js var PI = Math.PI; exports.area=function(r)returnPI*r*exports.circumference=functionreturn 2* PI *將這個(gè)文件存為 circle.js,并新建一個(gè) app.js 可以看到模塊調(diào)用也十分方便,只需要需要調(diào)用的文件即可在require 了這個(gè)文件

18、之后,定義在exports 對象上的方法便可以隨意調(diào)用。Node.js 將模塊的定義和調(diào)用都封簡單方便,從API 對用戶友好這一個(gè)角度來說,將這個(gè)文件存為 circle.js,并新建一個(gè) app.js 可以看到模塊調(diào)用也十分方便,只需要需要調(diào)用的文件即可在require 了這個(gè)文件之后,定義在exports 對象上的方法便可以隨意調(diào)用。Node.js 將模塊的定義和調(diào)用都封簡單方便,從API 對用戶友好這一個(gè)角度來說,Node.js 的模塊機(jī)制是Node.js 的模塊分為兩類,一類為原生)模塊,一類為文件模塊。原生模塊在 Node.js 源代碼編譯的時(shí)候編譯進(jìn)了進(jìn)制執(zhí)行文件,加載的速度最快。另

19、一類文件模塊是動(dòng)態(tài)加載的,加載速度比原生模塊慢。但是 Node.js 對原生模塊文件模塊都進(jìn)行了緩存,于是在第二次require 時(shí),是不會有重復(fù)開銷的。其中原生模塊都被定義lib 這文件模塊則不定性下面如何加載文件模塊開始談起。加載文件模塊的工作主要由原生模塊 module 來實(shí)現(xiàn)和完成,該原生模塊在啟動(dòng)時(shí)已經(jīng)被加載,進(jìn)程直接調(diào)用到 runMain 靜態(tài)方法_load 靜態(tài)方法在分析文件名并根據(jù)文件路徑緩存當(dāng)前模塊對象,該模塊實(shí)例對象則根據(jù)文件名加載實(shí)際上在文件模塊中,又分為 3 類模塊。這三類文件模塊以后綴來區(qū)分,Node.js .js。通過fs 模塊同js 文件并編譯執(zhí)行.node。通過

20、 C/C+進(jìn)行編寫的 Addon。通過dlopen 方法進(jìn)行加載.json文件,調(diào)用 加載varmodule=newModule(id,/ bootstrap maModule.runMain=function()/ Load the madlineargument. s.argv1, null, true);nodevarcircle=console.log(Theareaofacircleofradius4is+這詳細(xì)描述js 后綴的編譯過程。Node.js 在編譯js 文件的過程中實(shí)際完成的步驟有對js 文件內(nèi)容進(jìn)行頭尾包裝以app.js 為例,包裝之后的app.js 將會變成以下形式這

21、段代碼會通過 vm 原生模塊的hisContext 方法執(zhí)行(類似 eval,只是具有明確上下文,不污染全局),返回這詳細(xì)描述js 后綴的編譯過程。Node.js 在編譯js 文件的過程中實(shí)際完成的步驟有對js 文件內(nèi)容進(jìn)行頭尾包裝以app.js 為例,包裝之后的app.js 將會變成以下形式這段代碼會通過 vm 原生模塊的hisContext 方法執(zhí)行(類似 eval,只是具有明確上下文,不污染全局),返回一個(gè)具體的function 對象。最后傳入 module exports,require 方法,module名作為實(shí)參并執(zhí)行這就是為什么require并沒有定義在app.js文件中,但是這

22、個(gè)方法卻存在的Node.js的API文檔中可以看到還有 filename、 dirname、module、exports 幾個(gè)沒有定義但是卻存在的變量。其中 filename 和 dirname 在查找文件路徑的過程中分析得到后傳入的。module 變量是這個(gè)模塊對象自身,exports 是在module 的構(gòu)造函數(shù)中初始化的一個(gè)空對象(,而不是 null)在這個(gè)主文件中,可以通過require 方法去引入其余的模塊。而其實(shí)這個(gè) require 方法實(shí)際調(diào)用的就是load load 方法在載入、編譯、緩存了 module 后,返回module 的exports 對象。這就是circle.js

23、文件中只有定義在以上所描述的模塊載入機(jī)制均定義在lib/module.js 中由于Node.js 中存在 4 類模塊(原生模塊和 3 種文件模塊),盡管require 雜的,其加載優(yōu)先級也各自不同Node.js的事件Node.js在這句近/joyent/node)上有著一句短短的介紹:Evented I/O for V8 JavaScript語的句子卻道盡了 Node.js 自身的特色所在:基于 V8 引擎實(shí)現(xiàn)的事件驅(qū)動(dòng)IO。在本文的這部分內(nèi)容中我來揭開這Evented Node.js 能夠在眾多的后端JavaScript 技術(shù)之中脫穎而出,正是因其基于事件的特點(diǎn)而受到歡迎。拿 Rhino 來

24、做比較可以看出Rhino 引擎支持的后端JavaScript 擺脫不掉其他語言同步執(zhí)行的影響,導(dǎo)致 JavaScript 在后端編程與前端端編程中,事件的應(yīng)用十分廣泛,DOM 上的各種事件。之間有著十分顯著的差別,在編程模型上無法形Ajax 大規(guī)模應(yīng)用之后,異步請求更得到廣泛的認(rèn)同,而 Ajax 亦是基于事件機(jī)制的。在Rhino 中,文等操作,之類的服務(wù)語言的成熟度媲美性能也沒有值得可圈可點(diǎn)的部分。直到Ryan Dahl 2009 Node.js 后,后端JavaScript 才走出其迷局。的推出,我覺得該變了兩個(gè)狀況了前后端JavaScript 的編程模型利用事件機(jī)制充分利用用異步IO 突破

25、單線程編程模型的性能瓶頸,使得 JavaScript 在后端達(dá)到實(shí)用價(jià)值(function(exports,require,module, filename, varcircle =console.log(Theareaofacircleofradius4is+有了第二次瀏覽器大戰(zhàn)中的佼佼者 V8 的適時(shí)助力,使得Node.js 接受。這一點(diǎn)從 Node.js 項(xiàng)目在上的流行度和NPM 上的庫的數(shù)量可見一斑至于Node.js為何會選擇Evented I/O for V8 JavaScript 的結(jié)構(gòu)和形式來有了第二次瀏覽器大戰(zhàn)中的佼佼者 V8 的適時(shí)助力,使得Node.js 接受。這一點(diǎn)從 N

26、ode.js 項(xiàng)目在上的流行度和NPM 上的庫的數(shù)量可見一斑至于Node.js為何會選擇Evented I/O for V8 JavaScript 的結(jié)構(gòu)和形式來實(shí)現(xiàn),可以參見一下2011 年初對作者Ryan 的一次采訪/2011/01/31/node-js- erview-4-questions-with-creator-ryan-。Node.js 中大部分的模塊,都繼承自Event 模塊)。Event 模(events.EventEmitter)是一個(gè)簡單的事removeAllListeners,emit 等基本的事器模式的實(shí)現(xiàn)。具有 模式的方法實(shí)現(xiàn)。它與前端 DOM 層捕獲等屬于 DOM

27、 的事件行preventDefault()、stopPropagation()、 stopImmediatePropagation() 等理事件傳遞的方法從另一個(gè)角度來看,事件模式也是一種事件鉤子(hook)的機(jī)制,利用事件鉤子導(dǎo)數(shù)據(jù)或狀態(tài)給外部調(diào)者。Node.js 中的很多對象,大多具有黑盒的特點(diǎn),功能點(diǎn)較少,如果不通過事件鉤子的形式,對象運(yùn)行期間的中間或件是如何啟動(dòng)和執(zhí)行的,只關(guān)注在需要的事件點(diǎn)上即可HTTP request 需過于關(guān)注error,data 這些業(yè)務(wù)事件點(diǎn)即可,至的流程如何,varoptions=host:port:method: varreq=http.request(o

28、ptions,function console.log(SUS: + res.sconsole.log(HEADERS:+JSON.stringify(res.headers); res.on(data,functionconsole.log(BODY:+req.on(error,function(e)console.log(problemwithrequest:+/ write daorequestbody 值得一提的是如果對一個(gè)事件添加了超過10 個(gè)將會得到一條警告,這一處設(shè)計(jì)與Node.js 自身單線程運(yùn)行有關(guān)設(shè)計(jì)者認(rèn)為太多,可能導(dǎo)致內(nèi)存泄漏,所以存在這樣一個(gè)警告。調(diào)用可以將這個(gè)限制去掉

29、其次,為Node.js 的程序的健壯性,EventEmitter 對象對error 值得一提的是如果對一個(gè)事件添加了超過10 個(gè)將會得到一條警告,這一處設(shè)計(jì)與Node.js 自身單線程運(yùn)行有關(guān)設(shè)計(jì)者認(rèn)為太多,可能導(dǎo)致內(nèi)存泄漏,所以存在這樣一個(gè)警告。調(diào)用可以將這個(gè)限制去掉其次,為Node.js 的程序的健壯性,EventEmitter 對象對error 事件進(jìn)行了特殊對待。如果運(yùn)行期間的錯(cuò)誤觸發(fā)error 事件。EventEmitter 會檢查是否有對error 事件添加過,如果添加了,這個(gè)錯(cuò)誤將會交由該處理,則,這個(gè)錯(cuò)誤將會作為異常拋出。如果外部沒有捕獲這個(gè)異常,將會引起線程的退出實(shí)現(xiàn)一個(gè)繼承

30、了 EventEmitter 類是十分簡單的,以下是Node.js 中流對象繼承EventEmitter 在工具模塊中封裝了繼承的方法,所以此處可以很便利地調(diào)用。程序員可以通過這樣的方式輕松繼多事件在略微大一點(diǎn)的應(yīng)用中,數(shù)據(jù)與 Web 服務(wù)器之間的分離是必然的,、等。這樣的優(yōu)勢在數(shù)據(jù)源,并且可以為相同數(shù)據(jù)源制定各種豐富的客戶端程序。以Web應(yīng)用為例,在渲染一張頁面的時(shí)候,通常需要從多個(gè)數(shù)據(jù)源拉取數(shù)據(jù),并最終渲染至客戶端。Node.js 在這種場景中可以很自然很方便的同時(shí)并行發(fā)起對多個(gè)數(shù)據(jù)源的請求api.getUser(username, function (profile) /Gottheap

31、i.getTimeline(username, function (timeline) /Gottheapi.getSkin(username,function(skin)/Gotthefunction util.inherits(Stream, Node.js 通過異步機(jī)制使請求之間無阻塞,達(dá)到并行請求的目Node.js 通過異步機(jī)制使請求之間無阻塞,達(dá)到并行請求的目的,有效的調(diào)用下層資源。但是,這個(gè)場景是于多個(gè)事件響應(yīng)結(jié)果的協(xié)調(diào)并非被也許會被變成以下情況原生優(yōu)雅地支持。為了達(dá)到三個(gè)請求都得到結(jié)果后才進(jìn)行下一個(gè)步驟,程這將導(dǎo)致請求變?yōu)榇羞M(jìn)行,無法最大化利用底層的 API 服務(wù)器為解決這類問

32、題,我曾寫作一個(gè)模塊/JacksonTian/eventproxy)來實(shí)現(xiàn)多事件協(xié)作以下為上面代碼的改進(jìn)版EventProxy 也是一個(gè)簡單的事件偵聽者模式的實(shí)現(xiàn)Node.js 的EventEmitter 中。但是卻提供了比EvtEmitter更強(qiáng)大的功能,且API保持與EvtEmittr一致,與No.s的思路保持契合,并可以適用端中。all 方法是指偵聽完profile、timeline、skin 三個(gè)方法后,執(zhí)行回調(diào)函數(shù),并將偵聽接收到的數(shù)據(jù)傳入最后還介紹一種解決多事件協(xié)作的方案/JeffreyZhao/jscex )。Jscex 通過運(yùn)行時(shí)編譯的路(需要時(shí)也可在運(yùn)行前編譯),將同步思 來

33、寫,可以享受到同步思 的便利寫作,異步執(zhí)行的高效性能。如果通Jscex 編寫,將會是以下形式vardata$await(Task.whenAll(profile: varproxy=newproxy.all(profile,timeline,skin,function(profile,timeline,skin)/api.getUser(username, function proxy.emit(profile,api.getTimeline(username, function proxy.emit(timeline,api.getSkin(username, function proxy.

34、emit(skin,api.getUser(username,functionapi.getTimeline(username,function(timeline) api.getSkin(username, function (skin) / 此節(jié)感謝作者)的指正和幫助利用事件隊(duì)列解決雪崩問題所謂雪崩問題,是在緩存失效的情景下,大并發(fā)整體響應(yīng)緩慢。那么在 Node.js 中如何應(yīng)付這種情景呢量巨大,同一句 以上是一句數(shù)據(jù)庫查詢的調(diào)用,如果站點(diǎn)剛好啟動(dòng),這時(shí)候緩存中是不存在數(shù)據(jù)的,而此節(jié)感謝作者)的指正和幫助利用事件隊(duì)列解決雪崩問題所謂雪崩問題,是在緩存失效的情景下,大并發(fā)整體響應(yīng)緩慢。那么在

35、 Node.js 中如何應(yīng)付這種情景呢量巨大,同一句 以上是一句數(shù)據(jù)庫查詢的調(diào)用,如果站點(diǎn)剛好啟動(dòng),這時(shí)候緩存中是不存在數(shù)據(jù)的,而如會但是這種情景,連續(xù)的多次調(diào)用 select 后續(xù)的引入事件隊(duì)列吧是沒varproxy=newvar us= varselect=function callback);ifready)ussus=db.select(SQL,functionproxy.emit(selected,varus=varselect=function if (sus=ready) us = pending;db.select(SQL,functionus = ready;varselec

36、t=functiondb.select(SQL,function(results) skin:/ 使用file, imeline,/這里利用了EventProxy 對象的once 方法,將所有請求的回調(diào)都壓入這里利用了EventProxy 對象的once 方法,將所有請求的回調(diào)都壓入事件隊(duì)列中,并利用其執(zhí)行一次就會將監(jiān)視器移除的特點(diǎn),保證每一個(gè)回調(diào)只會被執(zhí)行一次。對于相同SQL 只有一次,在這查期間到來的調(diào)用,只需在隊(duì)列中等待數(shù)據(jù)就緒即可,節(jié)省了重復(fù)的數(shù)據(jù)庫調(diào)用開銷。由于 Node.js 單線程執(zhí)行的原因,處無需擔(dān)心狀態(tài)問題。這種方式其實(shí)調(diào)用的場景中,即使外部沒有緩存策略,也能有效節(jié)省重復(fù)開銷

37、。此處也可以用 EventEmitter 替代EventProxy,不過可能存在setMaxListeners(0)警告,需要從文件模塊緩存中從原生原生模塊的優(yōu)先級僅次于文件模塊緩存的優(yōu)先require 方法文件名之后,優(yōu)先檢查模塊是否在原生從原生原生模塊的優(yōu)先級僅次于文件模塊緩存的優(yōu)先require 方法文件名之后,優(yōu)先檢查模塊是否在原生模塊列表中以http 模塊為例,盡管下存在一個(gè) http/http.js/http.node/http.json 文件,require(“http”)都不會從這些文件中載,而是從原生模塊中加載載和執(zhí)行從文件當(dāng)文件模塊緩存中不存在,而且不是原生模塊的時(shí)候,No

38、de.js require 方法傳入的參數(shù),并從文件系統(tǒng)中加載際的文件,加載過程中的包裝和編譯細(xì)一節(jié)中已經(jīng)介紹過,這詳細(xì)描述查找文件模塊的過程,其中,有一些細(xì)節(jié)值得知曉http、fs、path 等,原生模塊./mod 或./mod在進(jìn)入路徑查找之前有必要描述一下modlepth這個(gè)o.s中的概念。對于每一個(gè)被加載的文件模塊,創(chuàng)建這個(gè)模塊對象的時(shí)候,這個(gè)模塊便會有一個(gè)pts 屬性,其值根據(jù)當(dāng)前文件的路徑計(jì)算得到。創(chuàng)建 modlpthjs 這一個(gè)文件,其內(nèi)容為中執(zhí)行node modulepath.js 命令,將得到其放到任意一Windows 下可以看出module 錄下的 開始查找 下的;然后依次

39、進(jìn)入,查找父;依次迭代,直到除此之外還有一個(gè)全局 path,是當(dāng)前node 執(zhí)行文件的相(././lib/node)。如果在環(huán)境變量中設(shè)置和的話,整個(gè)路徑還包含NODE_PATH 和下的.node_libraries 與.node_modules其最終值大致如下 c:nodejsnode_modules, c:node_modules /home/jackson/research/node_modules, /node_modules 初探Node.js 的異步I/O 實(shí)現(xiàn)異步在操作系統(tǒng)中,程序運(yùn)行的空間分為內(nèi)核空間和用戶空間初探Node.js 的異步I/O 實(shí)現(xiàn)異步在操作系統(tǒng)中,程序運(yùn)行的空

40、間分為內(nèi)核空間和用戶空間常常提起的異步 I/O,其實(shí)質(zhì)是用戶空間中的程序不依賴內(nèi)核空中的/O操作實(shí)際完成,即可進(jìn)行后續(xù)任務(wù)。以下偽代碼模仿了一個(gè)從磁盤上獲取文件和一個(gè)從取文件的操。異步/O 效果就是geileomNt 的調(diào)用不依賴于gtle 調(diào)用的結(jié)束。如果以上兩個(gè)任務(wù)的時(shí)間分別為 m n。采用同步方式的程序要完成這兩個(gè)任務(wù)的時(shí)間總花銷會是 m + n。但是如果采用異步方式的程序,在兩種I/O 可以并行的狀況下(比如網(wǎng)絡(luò) I/O 與文件I/O),時(shí)間開銷將會減小為max(m, n)有的語言為了設(shè)計(jì)得使應(yīng)用程序調(diào)用方便,將程序設(shè)計(jì)為同步 I/O 的模型。這意味著程序中的后續(xù)任務(wù)都需要等待 的完成

41、。在等待I/O完成的過程中,程序無法充分利用CPU。為了充分利用CPU,和使I/O可以并行,目前有兩種方式可以達(dá)到目的:多線程單進(jìn)多線程的設(shè)計(jì)之處就是為了在共享的程序空間中,實(shí)現(xiàn)并行處理任務(wù),從而達(dá)到充分利CPU 的效果。多程的缺點(diǎn)在于執(zhí)行時(shí)上下文交換的開銷較大,和狀態(tài)同步(鎖。同樣它也使得程序的編寫和調(diào)用雜化單線程多進(jìn)為了避免多線程造成的使用不便問題,有的語言選擇了單線程保持調(diào)用簡單化,采用啟動(dòng)多進(jìn)程的方式來到充分利用CPU 總體的并行處理能力。 它的缺點(diǎn)在于業(yè)務(wù)邏輯復(fù)雜時(shí)(涉及多個(gè)I/O 調(diào)用),因?yàn)閯?wù)邏輯不能分布到多個(gè)進(jìn)程之間,事務(wù)處理時(shí)長要遠(yuǎn)遠(yuǎn)大于多線程模式前者在性能優(yōu)化上還有回旋的余

42、地,后者的做法純粹是一種加三倍服務(wù)器的行為而且現(xiàn)在的大型 Web 應(yīng)用中,單機(jī)的情形是十分稀少的,一個(gè)事務(wù)往往需網(wǎng)絡(luò)幾次才能完成最終處理。如果絡(luò)速度不夠理想,m 和 n 值都將會變大,這時(shí)同步I/O 的語言模型將會露出其最脆弱的狀這種場景下的異步/O將會體現(xiàn)其優(yōu)勢,m(m,)的時(shí)間開銷可以有效地緩解m和n值增長帶來的性能問題。而當(dāng)并行任務(wù)的時(shí)候,m + n + 與m(m, n, )之間的孰優(yōu)孰劣更是一目了然。從這個(gè)公式中,可以了解到異步 /O 在分布式環(huán)境中是多么重要,而天然地支持這種異步I/O,這是眾多云計(jì)算廠商對其青睞的根本原因聽到Node.js 時(shí)常常會聽到異步,非阻塞,回調(diào),事件這些詞

43、語混合在一聽到Node.js 時(shí)常常會聽到異步,非阻塞,回調(diào),事件這些詞語混合在一起。其中,異步與非阻塞聽起來并行 I/O I/O 乎是同一回事。從實(shí)際效果的角度說,異步和非阻塞都達(dá)到/同步和阻塞/I/O 的阻塞與非阻阻塞模式的/O/O完成。同時(shí)操作系統(tǒng)也支持將/O操作設(shè)置為非阻塞模式,這時(shí)應(yīng)用程序的調(diào)用將可能在沒有拿到真正數(shù)據(jù)時(shí)就立即返回了,為此應(yīng)用程序需要多次調(diào)用才能確認(rèn)/O 操作完全完成。I/O 的同步與異I/O 的同步與異步出現(xiàn)在應(yīng)用程序中。如果做阻塞 I/O 調(diào)用,應(yīng)用程序況。相反,I/O 異步 I/O 與輪詢技術(shù)當(dāng)進(jìn)行非阻塞I/O 調(diào)用時(shí),要讀到完整的數(shù)據(jù),應(yīng)用程序需要進(jìn)行多次輪詢

44、,才能操作數(shù)據(jù)完成,以進(jìn)行下一步輪詢技術(shù)的缺點(diǎn)在于應(yīng)用程序要主動(dòng)調(diào)用,會造成占用較時(shí)間片,性能較為低下。現(xiàn)存的輪詢技術(shù)有以下這些read 是性能最低的一種,它通過重復(fù)調(diào)用來檢查 I/O 的狀態(tài)來完成完整。select 是一種改進(jìn)方案,通過對文件述符上的事件狀態(tài)來進(jìn)行判斷。操作系統(tǒng)還提供了 poll、epoll 等多路復(fù)用技術(shù)來提高性能輪詢技術(shù)滿了異步/O確保獲取完整數(shù)據(jù)的保證。但是對于應(yīng)用程序而言,它仍然只能算時(shí)一種同步仍然需要主去判斷/O 的狀態(tài),依舊花費(fèi)了很多CU 時(shí)間來等待。法重復(fù)調(diào)用read 進(jìn)行輪詢直到最終成功,用戶程序會占用較多 CPU,性能較為低下。而實(shí)際上操作系統(tǒng)提了 sele

45、ct 方法來代替這種重復(fù)read 輪詢進(jìn)行狀態(tài)判斷。通過檢查文件描述符上的事件狀態(tài)來進(jìn)行判斷數(shù)據(jù)否完。但是對于應(yīng)用程序而言它仍然只能算是一種同步,因?yàn)閼?yīng)用程序仍然需要主動(dòng)去判斷 I/O 的狀態(tài),依舊費(fèi)了很多CPU 時(shí)間等待,select 理想的異步I/O 應(yīng)該是應(yīng)用程序發(fā)起異步調(diào)用,而不需要進(jìn)行輪詢,進(jìn)而處理下一個(gè)任務(wù),只需在 I/O 幸運(yùn)的是,在 Linux 下存在一種這種方式,它原生提供了一種異步非阻塞 I/O 方式(幸運(yùn)的是,在 Linux 下存在一種這種方式,它原生提供了一種異步非阻塞 I/O 方式(AIO)即是通過信號或回調(diào)來傳數(shù)據(jù)的不幸的是,只有 Linux 下有這么一種支持,而且

46、還有缺陷(AIO 僅支持內(nèi)核I/O 中的O_DIRECT 方式以上都是基于非阻塞/O進(jìn)行的設(shè)定。另一種理想的異步/O是采用阻塞/O,但加入多線程,將/O操作分到多個(gè)線程上,利用線程之間的通信來模擬異步。lic 的AO便是這樣的典型/developerworks/linux/library/l-async/。然而遺憾在于,它存在一些難以忍受的缺陷和bug,導(dǎo)致無簡單的概述為下沒有完美的異步I/O 支持所幸的是,libev 的作者 Marc Alexander Lehmann 重新實(shí)現(xiàn)了一個(gè)異步I/O 的庫:libeio。libeio 實(shí)質(zhì)依然是采用線與阻塞 I/O 模擬出來的異步I/O那么在 下

47、的狀況如何呢?而實(shí)際上,Windows 有一種獨(dú)有的內(nèi)核異步IO 方案:IOCP。IOCP 的思路是正的異步I/O 方案,調(diào)用異步方法,然后等待 I/O 完成通知。依舊是通過線程實(shí)現(xiàn),不同在于這些線程核接手管理。IOCP 的異步模型與Node.js 的異步調(diào)用模型已經(jīng)十分近似以上兩種方是Node.js 選擇的異步I/O 方案。由于和的差異,Node.js提供了libuv來作與下層的 libeio/libev IOCP 之兼容性的判斷都由這一層次來完成,保證上層的 間各自獨(dú)立。Node.js 在編譯期間會判條件,選擇性編譯 或是下通過解釋W(xué)indows 下Node.js 異步I/O(IOCP)的

48、簡單下通過解釋W(xué)indows 下Node.js 異步I/O(IOCP)的簡單例子來探尋一下從 JavaScript 代碼到系統(tǒng)內(nèi)核之間發(fā)生了什么Node.js 的異步I/O 很多同學(xué)在遇見 Node.js 后必然產(chǎn)生過對回調(diào)函數(shù)究竟如何被調(diào)用產(chǎn)生過好奇。在文件 I/O 這一塊與普通的業(yè)務(wù)邏輯以最簡單回調(diào)函數(shù)不同在于它不是自己的代碼所觸發(fā),而是系統(tǒng)調(diào)用結(jié)束后,由系統(tǒng)觸發(fā)的。下方法來作為例子,探索Node.js 與底層之間是如何執(zhí)行異步I/O 調(diào)用和回調(diào)函數(shù)究竟是如何被調(diào)用執(zhí)行的fs.open 的作用是根據(jù)指定路徑和參數(shù),去打開一個(gè)文件,從而得到一個(gè)文件描述符,是后續(xù)所有 I/O fs.open=

49、function(path,flags,mode,callback=argumentsarguments.length-1; if (typeof(callback) != function)callback= mode=modeNum(mode,438在JavaScript 層面上調(diào)用的fs.open 方法最終都透過node_file.cc 調(diào)用到了libuv 中的uv_fs_open 方法,這里 libuv 作封裝層,分別寫了在JavaScript 層面上調(diào)用的fs.open 方法最終都透過node_file.cc 調(diào)用到了libuv 中的uv_fs_open 方法,這里 libuv 作封

50、裝層,分別寫了兩下的代碼實(shí)現(xiàn),編譯之后,只會存在一種實(shí)現(xiàn)被調(diào)用在uv_fs_open 的調(diào)用過程中,Node.js 創(chuàng)建了一個(gè) FSReqWrap 請求對象。從JavaScript plete_sym 裝在這個(gè)請求對象中,其中回調(diào)函數(shù)則被設(shè)置在這個(gè)對象對象包裝完畢后,調(diào)用 QueueUserWorkItem 方法將這個(gè) FSReqWrap 接受三個(gè)參數(shù),第一個(gè)是要執(zhí)行的方法,第二個(gè)是方法的上下文,第三個(gè)是執(zhí)行的標(biāo)志。當(dāng)線池中有可用線程的時(shí)候調(diào)用uv_fs_thread_proc 方法執(zhí)行。該根據(jù)傳入的類型調(diào)用相應(yīng)的底層函數(shù),以 QueueUserWorkItem(&uv_fs_thread_p

51、roc, req, req_wrap-object_-plete_sym, 為例,實(shí)際會調(diào)用到open 方法。調(diào)用完畢之后,會將獲取的結(jié)果設(shè)置在 req-result 上。然后調(diào)pletionS us 通的IOCP為例,實(shí)際會調(diào)用到open 方法。調(diào)用完畢之后,會將獲取的結(jié)果設(shè)置在 req-result 上。然后調(diào)pletionS us 通的IOCP 對象操作已經(jīng)完成pletionS us方法的作用是向創(chuàng)建的IOCP上相關(guān)的線程通信,線程根據(jù)執(zhí)行狀況和傳入的參數(shù)判定退至此,由層面發(fā)起的異步調(diào)用第一階段就此結(jié)束在調(diào)用uv_fs_open 方法的過程中實(shí)際上應(yīng)用到了事件循環(huán)。以在 了一個(gè)基于的事件

52、循環(huán)loop,并一直處于執(zhí)行狀態(tài)下的實(shí)現(xiàn)中,啟動(dòng) Node.js 時(shí),便創(chuàng)每次循環(huán)中,它會調(diào)用 IOCP 相關(guān)的pletionS us方法檢查是否線程池中有執(zhí)行完的請求,如果存在poll 操作會將請求對象加入到 loop 的pending_reqs_tail 屬性上。 另一邊這個(gè)循環(huán)也會不斷檢查 loop 對象,如果有可用的請求對象,就取出請求對象的result 屬性作為結(jié)果傳遞plete_sym 執(zhí)行以此達(dá)到調(diào)用 JavaScript 中傳入的回調(diào)函數(shù)的目的。 至此,整個(gè)異步I/O us(loop)-iocp, 0, 0, &(req)-了Node.js 的異步I/O 模型的兩了Node.j

53、s 的異步I/O 模型的兩個(gè)基本元素,這也是典型的消費(fèi)者生產(chǎn)者場景。在 Windows 事件循環(huán)和請求對通過IOCP pletionS us、QueueUserWorkItem方法與事件循環(huán)實(shí)對于下,這個(gè)流程的不同之處在與實(shí)現(xiàn)這些功能的方法是由 libeio 和libev 提供簡而言之,如果 require 絕對路徑的文件,查找時(shí)不會去遍歷每一個(gè) ,其速度最快。其余流程如下從module path 數(shù)組中嘗試添加.js、.json、后綴后查找,如果存在文件,則結(jié)束查找。如果不存在,則進(jìn)行下一條嘗試將 require 的參數(shù)作為一個(gè)包來進(jìn)行查找下的 package.json 文件,取得簡而言之,

54、如果 require 絕對路徑的文件,查找時(shí)不會去遍歷每一個(gè) ,其速度最快。其余流程如下從module path 數(shù)組中嘗試添加.js、.json、后綴后查找,如果存在文件,則結(jié)束查找。如果不存在,則進(jìn)行下一條嘗試將 require 的參數(shù)作為一個(gè)包來進(jìn)行查找下的 package.json 文件,取得main 參數(shù)指定的文件試查找該文件,如果存在,則結(jié)束查找。如果不存在,則進(jìn)行第 3 條查找如果繼續(xù)失敗,則取出module path 數(shù)組中的下一作為基準(zhǔn)查找,循1 5 個(gè)步驟如果繼續(xù)失敗,循環(huán)第16個(gè)步驟,直到modulepath中的最后一個(gè)值整個(gè)查找過程十分類似原型鏈的查找和作用域的查找。所

55、對路徑查找實(shí)現(xiàn)了緩存機(jī)制,否則由于每次判斷徑都是同步阻塞式進(jìn)行,會導(dǎo)致嚴(yán)重的性能消耗前面提到,JavaScript 缺少包結(jié)構(gòu)。CommonJS /wiki/Packages/1.0 )。而NPM 的出現(xiàn)則是為了在CommonJS 規(guī)范的基礎(chǔ)上,實(shí)現(xiàn)解決的安裝卸載,依賴管理,版本管理等問題。require 的查找機(jī)制明了之后來看一下包的細(xì)節(jié)一個(gè)符合CommonJS 一個(gè)package.json 文件應(yīng)該存在于包頂二進(jìn)制文件應(yīng)該包含在 下下JavaScript 代碼應(yīng)該包文檔應(yīng)該在下下單元測試應(yīng)該在下由上文的require 的查找過程可以知道,Node.js 在沒有找到目標(biāo)文件時(shí),會將當(dāng)當(dāng)作一個(gè)

56、包來嘗試加載,所以ca.son文件中最重要的一個(gè)字段就是mi。而實(shí)際上,這一處是No.s的擴(kuò)展,標(biāo)準(zhǔn)定義中并不包含此字段,對于reire,只需要minCommoJS為package.json 文件定義了如下一些必須的字段name。包名,需要在NPM description。包簡介。通常會顯示在一些列表中),通常為x.y.z。該版本號十分重要,常常用。版本號。一個(gè)語義化的版本號一些版本控制的場合keywords。關(guān)鍵字?jǐn)?shù)組。用于 NPM 中的分類搜索ma ainers。者的數(shù)組。數(shù)組元素是一個(gè)包含 name、web 三個(gè)屬性的JSON 對象contributors如果提交的 patch merge 進(jìn)分支的話,就應(yīng)當(dāng)加上這個(gè)貢獻(xiàn) 式包含 name 。如contributors: name:Jackson:bugs。一個(gè)可以提交bug 的 URL 地址??梢允青]件地址),也可以是網(wǎng)頁地()licenses。包所使用

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論