<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 模擬技術(shù) > 設(shè)計(jì)應(yīng)用 > 為什么向后端工程師推薦Node.js

          為什么向后端工程師推薦Node.js

          作者: 時(shí)間:2012-12-12 來(lái)源:網(wǎng)絡(luò) 收藏

          科普文一則,說(shuō)說(shuō)我對(duì).的一些認(rèn)識(shí),以及我作為前端為什么會(huì)向后端推薦.。
          . 是服務(wù)器端的 JavaScript 運(yùn)行環(huán)境,它具有無(wú)阻塞(non-blocking)和事件驅(qū)動(dòng)(event-driven)等的特色,Node.js 采用V8引擎,同樣,Node.js實(shí)現(xiàn)了類似 Apache 和 nginx 的web服務(wù),讓你可以通過(guò)它來(lái)搭建基于 JavaScript的Web App。”
          我想不僅僅是Node.js,當(dāng)我們要引入任何一種新技術(shù)前都必須要搞清楚幾個(gè)問(wèn)題:
          1. 我們遇到了什么問(wèn)題?
          2. 這項(xiàng)新技術(shù)解決什么問(wèn)題,是否契合我們遇到的問(wèn)題?
          3. 我們遇到問(wèn)題的多種解決方案中,當(dāng)前這項(xiàng)新技術(shù)的優(yōu)勢(shì)體現(xiàn)在哪兒?
          4. 使用新技術(shù),帶來(lái)哪些新問(wèn)題,嚴(yán)重么,我們能否解決掉?
          我們的問(wèn)題:Server端阻塞
          Node.js被設(shè)計(jì)用來(lái)解決服務(wù)端阻塞問(wèn)題.下面通過(guò)一段簡(jiǎn)單的代碼解釋何為阻塞:

          1
          2
          3
          4
          //根據(jù)ID,在數(shù)據(jù)庫(kù)中Persons表中查出Name
          var name = db.query(select name from persons where id=1);
          //進(jìn)程等待數(shù)據(jù)查詢完畢,然后使用查詢結(jié)果。
          output(name)



          這段代碼的問(wèn)題是在上面兩個(gè)語(yǔ)句之間,在整個(gè)數(shù)據(jù)查詢的過(guò)程中,當(dāng)前程序進(jìn)程往往只是在等待結(jié)果的返回.這就造成了進(jìn)程的阻塞.對(duì)于高并發(fā),I/O 密集行的網(wǎng)絡(luò)應(yīng)用中,一方面進(jìn)程很長(zhǎng)時(shí)間處于等待狀態(tài),另一方面為了應(yīng)付新的請(qǐng)求不斷的增加新的進(jìn)程.這樣的浪費(fèi)會(huì)導(dǎo)致系統(tǒng)支持QPS遠(yuǎn)遠(yuǎn)小于后端數(shù)據(jù)服 務(wù)能夠支撐的QPS,成為了系統(tǒng)的瓶頸.而且這樣的系統(tǒng)也特別容易被慢鏈接攻擊(客戶端故意不接收或減緩接收數(shù)據(jù),加長(zhǎng)進(jìn)程等待時(shí)間)。
          如何解決阻塞問(wèn)題
          可以引入事件處理機(jī)制解決這個(gè)問(wèn)題。在查詢請(qǐng)求發(fā)起之前注冊(cè)數(shù)據(jù)加載事件的響應(yīng)函數(shù),請(qǐng)求發(fā)出之后立即將進(jìn)程交出,而當(dāng)數(shù)據(jù)返回后再觸發(fā)這個(gè)事件并在預(yù)定好的事件響應(yīng)函數(shù)中繼續(xù)處理數(shù)據(jù):
          1
          2
          3
          4
          5
          6
          //定義如何后續(xù)數(shù)據(jù)處理函數(shù)
          function onDataLoad(name){
          output(name);
          }
          //發(fā)起數(shù)據(jù)請(qǐng)求,同時(shí)指定數(shù)據(jù)返回后的回調(diào)函數(shù)
          db.query(select name from persons where id=1,onDataLoad);



          我們看到若按照這個(gè)思路解決阻塞問(wèn)題,首先我們要提供一套高效的異步事件調(diào)度機(jī)制.而主要用于處理瀏覽器端的各種交互事件的JavaScript。相對(duì)于其他語(yǔ)言,至少有兩個(gè)關(guān)鍵點(diǎn)特別適合完成這個(gè)任務(wù)。
          為什么JS適合解決阻塞問(wèn)題
          首先JavaScript是一種函數(shù)式編程語(yǔ)言,函數(shù)編程語(yǔ)言最重要的數(shù)學(xué)基礎(chǔ)是λ演算(lambda calculus) — 即函數(shù)對(duì)象可以作為其他函數(shù)對(duì)象的輸入(參數(shù))和輸出(返回值)。
          這個(gè)特性使得為事件指定回調(diào)函數(shù)變得很容易。特別是JavaScript還支持匿名函數(shù)。通過(guò)匿名函數(shù)的輔助,之前的代碼可以進(jìn)行簡(jiǎn)寫如下:
          1
          2
          3
          db.query(select name from persons where id=1,function(name){
          output(name);
          });



          還有另一個(gè)關(guān)鍵問(wèn)題是,異步回調(diào)的運(yùn)行上下文保持(本文暫稱其為”狀態(tài)保持”)。我們先來(lái)看一段代碼來(lái)說(shuō)明何為狀態(tài)保持:
          1
          2
          3
          4
          5
          6
          7
          //傳統(tǒng)同步寫法:將查詢和結(jié)果打印抽象為一個(gè)方法
          function main(){
          var id = 1;
          var name = db.query(select name from persons where id= + id);
          output(person id: + id + , name: + name);
          }
          main();



          前面的寫法在傳統(tǒng)的阻塞是編程中非常常見(jiàn),但接下來(lái)進(jìn)行異步改寫時(shí)會(huì)遇到一些困擾:
          1
          2
          3
          4
          5
          6
          7
          8
          //異步寫法:
          function main(){
          var id = 1;
          db.query(select name from persons where id= + id,function(name){
          output(person id: + id + , name: + name);//n秒后數(shù)據(jù)返回后執(zhí)行回調(diào)
          });
          }
          main();



          細(xì)心的朋友可能已經(jīng)注意到,當(dāng)?shù)却薾秒數(shù)據(jù)查詢結(jié)果返回后執(zhí)行回調(diào)時(shí)?;卣{(diào)函數(shù)中卻仍然使用了main函數(shù)的局部變量”id”,而”id”似乎應(yīng) 該在n秒前走出其作用域。為什么此時(shí)”id”仍然可以訪問(wèn)呢,這是因?yàn)镴avaScript的另外一個(gè)重要語(yǔ)言特性:閉包(Closures)。接下來(lái)我 來(lái)詳解閉包的原委。
          在復(fù)雜的應(yīng)用中,我們一定會(huì)遇到這類場(chǎng)景。即在函數(shù)運(yùn)行時(shí)需要訪問(wèn)函數(shù)定義時(shí)的上下文數(shù)據(jù)(注意:一定要區(qū)分函數(shù)定義時(shí)和函數(shù)運(yùn)行時(shí)兩個(gè)不同的時(shí) 刻)。特別是在異步編程模型中,函數(shù)的定義和運(yùn)行又分處不同的時(shí)間段,那么保持上下文的問(wèn)題變得更加突出了。因?yàn)槲覀冊(cè)谌蝿?wù)執(zhí)行一半時(shí)把資源交出去沒(méi)有問(wèn) 題,但當(dāng)任務(wù)需要再次繼續(xù)時(shí)我們必須還原現(xiàn)場(chǎng)。
          在這個(gè)例子中,db.query作為一個(gè)公共的數(shù)據(jù)庫(kù)查詢方法,把”id”這個(gè)業(yè)務(wù)數(shù)據(jù)傳入給db.query,交由其保存是不太合適的。但我們可 以稍作抽象,讓db.query再支持一個(gè)需要保持狀態(tài)的數(shù)據(jù)對(duì)象傳入,當(dāng)數(shù)據(jù)查詢完畢后可以把這些狀態(tài)數(shù)據(jù)原封不動(dòng)的回傳。如下:
          1
          2
          3
          4
          5
          6
          7
          8
          9
          function main(){
          var id = 1;
          var currentState = new Object();
          currentState.person_id = id;
          db.query(select name from persons where id= + id, function(name,state){
          output(person id: + state.person_id + , name: + name);
          },currentState);//注意currentState是db.query的第三個(gè)參數(shù)
          }
          main();



          記住這種重要的思路,我們?cè)倏纯词欠襁€能進(jìn)一步的抽象?可以的,不過(guò)接下的動(dòng)作之前,我們還要了解在JavaScript中一個(gè)函數(shù)也是一個(gè)對(duì)象。 一個(gè)函數(shù)實(shí)例fn除了函數(shù)體的定義之外,我們?nèi)匀豢梢栽谶@個(gè)函數(shù)對(duì)象實(shí)例之本身擴(kuò)展其他屬性,如fn.a=1;受到這個(gè)啟發(fā)我們嘗試把需要保持的狀態(tài)直接 綁定到函數(shù)實(shí)例上:
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          function main(){
          var id = 1;
          var currentState = new Object();
          currentState.person_id = id;
          function onDataLoad(name){
          output(person id: + onDataLoad.state.person_id + , name: + name);
          }
          onDataLoad.state = currentState ;//為函數(shù)指定state屬性,用于保持狀態(tài)
          db.query(select name from persons where id= + id, onDataLoad);
          }



          我們做了什么?生成了currentState對(duì)象,然后在函數(shù)onDataLoad定義時(shí),將currentState綁定給 onDataLoad這個(gè)函數(shù)實(shí)例。那么在onDataLoad運(yùn)行時(shí),就可以拿到定義時(shí)的state對(duì)象了。JavaScript的閉包特性就是內(nèi)置了 這個(gè)過(guò)程而已。
          在每個(gè)JavaScript函數(shù)運(yùn)行時(shí),都有一個(gè)運(yùn)行時(shí)內(nèi)部對(duì)象稱為Execution Context,它包含如下Variable Object(VO,變量對(duì)象), Scope Chain(作用域鏈)和”this” Value三部分。如圖:

          上一頁(yè) 1 2 下一頁(yè)

          關(guān)鍵詞: Node js 工程師

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();