<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                #### 一個基礎的HTTP服務器 當我準備開始寫我的第一個“真正的”Node.js應用的時候,我不但不知道怎么寫Node.js代碼,也不知道怎么組織這些代碼。 我應該把所有東西都放進一個文件里嗎?網上有很多教程都會教你把所有的邏輯都放進一個用Node.js寫的基礎HTTP服務器里。但是如果我想加入更多的內容,同時還想保持代碼的可讀性呢? 實際上,只要把不同功能的代碼放入不同的模塊中,保持代碼分離還是相當簡單的。 這種方法允許你擁有一個干凈的主文件(main file),你可以用Node.js執行它;同時你可以擁有干凈的模塊,它們可以被主文件和其他的模塊調用。 那么,現在我們來創建一個用于啟動我們的應用的主文件,和一個保存著我們的HTTP服務器代碼的模塊。 在我的印象里,把主文件叫做index.js或多或少是個標準格式。把服務器模塊放進叫server.js的文件里則很好理解。 讓我們先從服務器模塊開始。在你的項目的根目錄下創建一個叫`server.js`的文件,并寫入以下代碼: ~~~ var http = require("http"); http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }).listen(8888); ~~~ 搞定!你剛剛完成了一個可以工作的HTTP服務器。為了證明這一點,我們來運行并且測試這段代碼。首先,用Node.js執行你的腳本: ~~~ node server.js ~~~ 接下來,打開瀏覽器訪問`http://localhost:8888/`,你會看到一個寫著`“Hello World”`的網頁。 這很有趣,不是嗎?讓我們先來談談HTTP服務器的問題,把如何組織項目的事情先放一邊吧,你覺得如何?我保證之后我們會解決那個問題的。 #### 分析HTTP服務器 那么接下來,讓我們分析一下這個HTTP服務器的構成。 第一行請求(require)Node.js自帶的 http 模塊,并且把它賦值給 http 變量。 接下來我們調用http模塊提供的函數: createServer 。這個函數會返回一個對象,這個對象有一個叫做 listen 的方法,這個方法有一個數值參數,指定這個HTTP服務器監聽的端口號。 咱們暫時先不管 http.createServer 的括號里的那個函數定義。 我們本來可以用這樣的代碼來啟動服務器并偵聽8888端口: ~~~ var http = require("http"); var server = http.createServer(); server.listen(8888); ~~~ 這段代碼只會啟動一個偵聽8888端口的服務器,它不做任何別的事情,甚至連請求都不會應答。 最有趣(而且,如果你之前習慣使用一個更加保守的語言,比如PHP,它還很奇怪)的部分是 `createServer()` 的第一個參數,**一個函數定義**。 實際上,這個函數定義是 createServer() 的第一個也是唯一一個參數。因為在JavaScript中,函數和其他變量一樣都是可以被傳遞的。 #### 進行函數傳遞 舉例來說,你可以這樣做: ~~~ function say(word) { console.log(word); } function execute(someFunction, value) { someFunction(value); } execute(say, "Hello"); ~~~ 請仔細閱讀這段代碼!在這里,我們把 say 函數作為execute函數的第一個變量進行了傳遞。這里傳遞的不是 say 的返回值,而是 say 本身! 這樣一來, say 就變成了execute 中的本地變量 someFunction ,execute可以通過調用 someFunction() (帶括號的形式)來使用 say 函數。 當然,因為 say 有一個變量, execute 在調用 someFunction 時可以傳遞這樣一個變量。 我們可以,就像剛才那樣,用它的名字把一個函數作為變量傳遞。但是我們不一定要繞這個“先定義,再傳遞”的圈子,我們可以直接在另一個函數的括號中定義和傳遞這個函數: ~~~ function execute(someFunction, value) { someFunction(value); } execute(function(word){ console.log(word) }, "Hello"); ~~~ 我們在 execute 接受第一個參數的地方直接定義了我們準備傳遞給 execute 的函數。 用這種方式,我們甚至不用給這個函數起名字,這也是為什么它被叫做 匿名函數 。 這是我們和我所認為的“進階”JavaScript的第一次親密接觸,不過我們還是得循序漸進。現在,我們先接受這一點:在JavaScript中,一個函數可以作為另一個函數接收一個參數。我們可以先定義一個函數,然后傳遞,也可以在傳遞參數的地方直接定義函數。 #### 函數傳遞是如何讓HTTP服務器工作的 帶著這些知識,我們再來看看我們簡約而不簡單的HTTP服務器: ~~~ var http = require("http"); http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }).listen(8888); ~~~ 現在它看上去應該清晰了很多:我們向 createServer 函數傳遞了一個匿名函數。 用這樣的代碼也可以達到同樣的目的: ~~~ var http = require("http"); function onRequest(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); } http.createServer(onRequest).listen(8888); ~~~ 也許現在我們該問這個問題了:我們為什么要用這種方式呢? #### 基于事件驅動的回調 這個問題可不好回答(至少對我來說),不過這是Node.js原生的工作方式。它是事件驅動的,這也是它為什么這么快的原因。 你也許會想花點時間讀一下`Felix Geisend?rfer`的大作`Understanding node.js`,它介紹了一些背景知識。 這一切都歸結于“Node.js是事件驅動的”這一事實。好吧,其實我也不是特別確切的了解這句話的意思。不過我會試著解釋,為什么它對我們用Node.js寫網絡應用(Web based application)是有意義的。 當我們使用 `http.createServer` 方法的時候,我們當然不只是想要一個偵聽某個端口的服務器,我們還想要它在服務器收到一個HTTP請求的時候做點什么。 問題是,這是異步的:請求任何時候都可能到達,但是我們的服務器卻跑在一個單進程中。 寫PHP應用的時候,我們一點也不為此擔心:任何時候當有請求進入的時候,網頁服務器(通常是Apache)就為這一請求新建一個進程,并且開始從頭到尾執行相應的PHP腳本。 那么在我們的`Node.js`程序中,當一個新的請求到達`8888`端口的時候,我們怎么控制流程呢? 嗯,這就是`Node.js/JavaScript`的事件驅動設計能夠真正幫上忙的地方了——雖然我們還得學一些新概念才能掌握它。讓我們來看看這些概念是怎么應用在我們的服務器代碼里的。 我們創建了服務器,并且向創建它的方法傳遞了一個函數。無論何時我們的服務器收到一個請求,這個函數就會被調用。 我們不知道這件事情什么時候會發生,但是我們現在有了一個處理請求的地方:它就是我們傳遞過去的那個函數。至于它是被預先定義的函數還是匿名函數,就無關緊要了。 這個就是傳說中的 回調 。我們給某個方法傳遞了一個函數,這個方法在有相應事件發生時調用這個函數來進行 回調 。 至少對我來說,需要一些功夫才能弄懂它。你如果還是不太確定的話就再去讀讀Felix的博客文章。 讓我們再來琢磨琢磨這個新概念。我們怎么證明,在創建完服務器之后,即使沒有HTTP請求進來、我們的回調函數也沒有被調用的情況下,我們的代碼還繼續有效呢?我們試試這個: ~~~ var http = require("http"); function onRequest(request, response) { console.log("Request received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started."); ~~~ 注意:在 onRequest (我們的回調函數)觸發的地方,我用 console.log 輸出了一段文本。在HTTP服務器開始工作之后,也輸出一段文本。 當我們與往常一樣,運行它node server.js時,它會馬上在命令行上輸出“Server has started.”。當我們向服務器發出請求(在瀏覽器訪問`http://localhost:8888/` ),“Request received.”這條消息就會在命令行中出現。 這就是事件驅動的異步服務器端JavaScript和它的回調啦! (請注意,當我們在服務器訪問網頁時,我們的服務器可能會輸出兩次“Request received.”。那是因為大部分瀏覽器都會在你訪問 http://localhost:8888/ 時嘗試讀取 http://localhost:8888/favicon.ico ) #### 服務器是如何處理請求的 好的,接下來我們簡單分析一下我們服務器代碼中剩下的部分,也就是我們的回調函數 onRequest() 的主體部分。 當回調啟動,我們的 onRequest() 函數被觸發的時候,有兩個參數被傳入: request 和 response 。 它們是對象,你可以使用它們的方法來處理HTTP請求的細節,并且響應請求(比如向發出請求的瀏覽器發回一些東西)。 所以我們的代碼就是:當收到請求時,使用` response.writeHead() `函數發送一個HTTP狀態200和HTTP頭的內容類型(content-type),使用` response.write() `函數在HTTP相應主體中發送文本“Hello World"。 最后,我們調用 response.end() 完成響應。 目前來說,我們對請求的細節并不在意,所以我們沒有使用 request 對象。 #### 服務端的模塊放在哪里 OK,就像我保證過的那樣,我們現在可以回到我們如何組織應用這個問題上了。我們現在在 server.js 文件中有一個非常基礎的HTTP服務器代碼,而且我提到通常我們會有一個叫 index.js 的文件去調用應用的其他模塊(比如 server.js 中的HTTP服務器模塊)來引導和啟動應用。 我們現在就來談談怎么把server.js變成一個真正的Node.js模塊,使它可以被我們(還沒動工)的 index.js 主文件使用。 也許你已經注意到,我們已經在代碼中使用了模塊了。像這樣: ~~~ var http = require("http"); ... http.createServer(...); ~~~ Node.js中自帶了一個叫做“http”的模塊,我們在我們的代碼中請求它并把返回值賦給一個本地變量。 這把我們的本地變量變成了一個擁有所有 http 模塊所提供的公共方法的對象。 給這種本地變量起一個和模塊名稱一樣的名字是一種慣例,但是你也可以按照自己的喜好來: ~~~ var foo = require("http"); ... foo.createServer(...); ~~~ 很好,怎么使用Node.js內部模塊已經很清楚了。我們怎么創建自己的模塊,又怎么使用它呢? 等我們把 server.js 變成一個真正的模塊,你就能搞明白了。 事實上,我們不用做太多的修改。把某段代碼變成模塊意味著我們需要把我們希望提供其功能的部分 導出 到請求這個模塊的腳本。 目前,我們的HTTP服務器需要導出的功能非常簡單,因為請求服務器模塊的腳本僅僅是需要啟動服務器而已。 我們把我們的服務器腳本放到一個叫做 start 的函數里,然后我們會導出這個函數。 ~~~ var http = require("http"); function start() { function onRequest(request, response) { console.log("Request received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started."); } exports.start = start; ~~~ 這樣,我們現在就可以創建我們的主文件 index.js 并在其中啟動我們的HTTP了,雖然服務器的代碼還在 server.js 中。 創建 index.js 文件并寫入以下內容: ~~~ var server = require("./server"); server.start(); ~~~ 正如你所看到的,我們可以像使用任何其他的內置模塊一樣使用server模塊:請求這個文件并把它指向一個變量,其中已導出的函數就可以被我們使用了。 好了。我們現在就可以從我們的主要腳本啟動我們的的應用了,而它還是老樣子: ~~~ node index.js ~~~ 非常好,我們現在可以把我們的應用的不同部分放入不同的文件里,并且通過生成模塊的方式把它們連接到一起了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看