Nodejs是javascript的運(yùn)行程序,使用Nodejs最大的優(yōu)點(diǎn)是可以讓javascript運(yùn)行在服務(wù)器端,NodeJS是基于chrome的v8架構(gòu)的,它主要的的特點(diǎn)是基于異步的I/O處理,所有的事件都會(huì)被事件循環(huán)器處理,當(dāng)事件完成通過回調(diào)函數(shù)來傳遞結(jié)果廊蜒,這和典型的Ajax請(qǐng)求一樣。這樣直接導(dǎo)致Node的程序都是單線程的蜗搔,單線程的優(yōu)點(diǎn)是程序設(shè)計(jì)簡單劲藐,不用考慮復(fù)雜的線程通信,這樣也就沒有所謂的死鎖問題樟凄,雖然Node是單線程聘芜,但由于其異步執(zhí)行的優(yōu)勢(shì),使得Node也可以輕松的實(shí)現(xiàn)并發(fā)缝龄。
NodeJS的安裝
直接通過 https://nodejs.org/en/ 網(wǎng)站即可下載Nodejs汰现,當(dāng)前的最新版本9.3.0,建議使用8.9.3穩(wěn)定版挂谍,下載NodeJS的時(shí)候依然建議下載非安裝版,選擇other download瞎饲。
之后選擇Binary (.zip)這個(gè)進(jìn)行下載
下載完成之后口叙,解壓,把Nodejs的安裝目錄添加到環(huán)境變量的path中嗅战,安裝就完成了(注意Nodejs中沒有bin路徑)妄田。
NPM簡介
要很好的使用npm,在目前的NodeJS中驮捍,npm是自動(dòng)安裝的疟呐,大家可以發(fā)現(xiàn)NodeJS目錄中有npm.cmd程序,這是一個(gè)可執(zhí)行文件东且,它用來運(yùn)行npm启具,npm是一個(gè)模塊管理工具,有點(diǎn)類似于maven珊泳,開發(fā)人員可以將模塊下載到項(xiàng)目中或者一個(gè)全局的位置鲁冯,全局的位置默認(rèn)會(huì)在NodeJS安裝目錄的node_modules
文件夾中。這里僅僅只介紹幾個(gè)簡單的命令色查,如果希望詳細(xì)研究NPM薯演,可以查詢npm的官方文檔。
通過命令npm -v
可以查詢npm的版本
>npm -v
5.5.1
使用npm install可以安裝模塊秧了,有一個(gè)非常好用的前臺(tái)模塊管理工具bower涣仿,我們安裝一下bower,通過如下命令可以安裝
D:\test (master -> origin)
> npm install bower -g
npm WARN deprecated bower@1.8.2: ...psst! Your project can stop working at any moment because its dependencies can change. Prevent this by migrating to Yarn: https://bower.io/blog/2017/how-to-migrate-away-from-bower/
D:\nodejs\bower -> D:\nodejs\node_modules\bower\bin\bower
+ bower@1.8.2
added 1 package in 30.176s
加上-g表示全局安裝示惊,安裝完成之后會(huì)存儲(chǔ)到nodejs目錄的node_modules文件夾中。如果不使用全局安裝會(huì)自動(dòng)安裝在本地目錄中愉镰。另外可以通過@來指定安裝的版本號(hào)
>npm install jquery@latest -g
+ jquery@3.2.1
added 1 package in 2.313s
已上安裝了jquery的最新版米罚。另外通過remove可以移除module
> npm remove bower -g
removed 1 package in 3.282s
npm就簡單介紹到這里,接下來開始我們的第一個(gè)nodejs的程序
nodejs起步
nodejs是一個(gè)javascript的運(yùn)行環(huán)境丈探,要運(yùn)行第一個(gè)helloworld的程序录择,首先建立一個(gè)js的文件,我建立了begin.js在該文件中寫了一行代碼
console.log("hello world!");
之后在該文件夾中使用node命令來執(zhí)行這個(gè)文件
E:\study\nodejs_2018\01_hellojs>node begin.js
hello world!
輸出了結(jié)果碗降,這也就表示Nodejs已經(jīng)成功完成安裝隘竭。
require介紹
在Nodejs中提供了require函數(shù)來加載另外一個(gè)模塊,這個(gè)模塊可以是通過npm下載的也可以是自定義模塊讼渊,首先我們自己定義一個(gè)函數(shù)模塊动看,創(chuàng)建method.js文件
exports.M = {
begin: function() {
console.log("begin js");
},
end: function () {
console.log("end js");
}
}
已上代碼通過exports生成了一個(gè)M模塊,里面有begin和end兩個(gè)方法爪幻。下面在一個(gè)module1.js文件中引入該模塊
var m = require("./methods")
console.log(m);
m.M.begin();
m.M.end();
通過require引入了該模塊菱皆,注意要加上./
须误,另外就是methods不加js,并且定義了變量m來存儲(chǔ)該模塊仇轻,此后即可通過m.M來引入模塊中的方法京痢。
查詢一下結(jié)果
E:\study\nodejs_2018\01_hellojs>node module1.js
{ method: { begin: [Function: begin], end: [Function: end] } }##顯示模塊中的值
begin js ##調(diào)用模塊的begin方法
end js
創(chuàng)建一個(gè)nodejs的server
Nodejs由于是javascript的運(yùn)行環(huán)境,所以我們可以直接將javascript運(yùn)行在服務(wù)器端篷店,接下來我們編寫一個(gè)server.js來啟動(dòng)一個(gè)簡單的服務(wù)祭椰。首先創(chuàng)建server.js文件,完成如下幾個(gè)步驟
1、引入http模塊
var http = require("http")
2疲陕、創(chuàng)建server
http.createServer(serverOk).listen(8088);
已上代碼創(chuàng)建了一個(gè)server方淤,當(dāng)server創(chuàng)建完成之后會(huì)執(zhí)行回調(diào)函數(shù)serverOk,該回調(diào)函數(shù)中有兩個(gè)參數(shù)一個(gè)是request鸭轮,另外一個(gè)是response臣淤。該server啟動(dòng)在8088端口中。
3窃爷、編寫回調(diào)函數(shù)
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
resp.write("hello nodejs!");
resp.end();
};
回調(diào)函數(shù)有兩個(gè)參數(shù)邑蒋,req等于request對(duì)象,resp等于response對(duì)象按厘,首先使用resp.writeHead()編寫簡單的輸出信息医吊,狀態(tài)為200,類型是原始類型逮京,并且輸出了hello nodejs卿堂,最后通過resp.end()結(jié)束輸出。
4懒棉、運(yùn)行
首先看看完整代碼
var http = require("http");
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
resp.write("hello nodejs!");
resp.end();
};
http.createServer(serverOk).listen(8088);
使用node運(yùn)行之后草描,只要在瀏覽器輸入localhost:8088,會(huì)看到"hello nodejs!"的字符輸出策严。
基于模塊來修改上一個(gè)程序
我們可以將創(chuàng)建服務(wù)器的這段代碼編寫到一個(gè)模塊中穗慕,首先創(chuàng)建server_module.js
var http = require("http");
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
resp.write("hello node module!");
resp.end();
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
這里變換了一種寫法,首先在exports前增加了module妻导,個(gè)人感覺這樣說明要清晰一些逛绵,當(dāng)然module是可以省略的,另外就是該module并沒有編寫具體的導(dǎo)出的名稱倔韭,此時(shí)可以直接調(diào)用术浪,該module中有兩個(gè)方法,startServer表示啟動(dòng)服務(wù)寿酌,此時(shí)回調(diào)serverOk寫在了模塊的外面胰苏,這表示serverOk是私有的,不會(huì)被導(dǎo)出(就當(dāng)前例子中份名,該方法也沒有導(dǎo)出的意義)碟联。調(diào)用代碼也比較簡單妓美,創(chuàng)建文件test.js
var Server = require("./server_model");
console.log(Server);//輸出確定僅僅導(dǎo)出startServer
Server.startServer(8099);
運(yùn)行之后訪問localhost的8099端口即可看到相應(yīng)的輸出。但這個(gè)server顯然有一個(gè)比較嚴(yán)重的問題鲤孵,就是他只能監(jiān)聽一個(gè)請(qǐng)求壶栋,另外就是不能渲染html。下面我們先來解決html的渲染問題普监。然后在解決路由問題
渲染html文件
渲染html是比較重要的一個(gè)步驟贵试,Nodejs通過文件的讀寫來完成該操作,首先需要引入fs這個(gè)模塊
var fs = require("fs");
接著通過fs.ReadFile可以讀取文件
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
}
resp.writeHead(200,{"Content-type":"text/html"});
resp.write(data);
resp.end();
});
第一個(gè)參數(shù)表示file的路徑凯正,第二個(gè)參數(shù)用來存儲(chǔ)傳入的數(shù)據(jù)毙玻,第三個(gè)參數(shù)就是回調(diào),回調(diào)中有兩個(gè)參數(shù)廊散,第一個(gè)表示error桑滩,如果發(fā)現(xiàn)錯(cuò)誤就會(huì)為第一個(gè)參數(shù)賦值,第二個(gè)參數(shù)表示如果成功返回的內(nèi)容允睹。代碼中首先判斷了是否有error运准,如果沒有error就直接輸出data,data就是讀取到的html的文件內(nèi)容缭受,注意content-type的類型必須修改為text/html胁澳。如果發(fā)現(xiàn)錯(cuò)誤直接顯示404.
完整代碼如下所示
var http = require("http");
var fs = require("fs");
function renderHTML(path,resp) {
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
} else {
resp.write(data);
}
resp.end();
});
}
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
//渲染hello.html
renderHTML("./hello.html",resp);
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
調(diào)用代碼和上一節(jié)類似,然后看一下hello.html文件并且完成服務(wù)器的啟動(dòng)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello html</h1>
</body>
</html>
此時(shí)啟動(dòng)米者,并且訪問localhost的8099即可顯示hello.html的內(nèi)容韭畸。
路由
這一小節(jié)將要實(shí)現(xiàn)不同的請(qǐng)求訪問不同的頁面,操作原理非常簡單蔓搞,通過request的url可以獲取訪問路徑胰丁,通過url模塊中的parse方法可以將url轉(zhuǎn)換為json對(duì)象,其中pathname可以獲取訪問的路徑變量喂分。將server_module.js的代碼稍作調(diào)整即可
var http = require("http");
var fs = require("fs");
var url = require("url")
function renderHTML(path,resp) {
//路徑判斷
if(path=="/"||path=="") {
path = "./index.html";
} else {
path = "./"+path+".html";
}
//console.log(path);
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
} else {
resp.write(data);
}
resp.end();
});
}
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/html"});
//獲得訪問的路徑隘马,如果輸入localhost:8089/abc/bbd會(huì)得到/abc/bbd
var pathname = url.parse(req.url).pathname;
renderHTML(pathname,resp);
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
這里簡單實(shí)現(xiàn)了Nodejs的基本流程,但在實(shí)際開發(fā)中一般都不會(huì)使用原生的方法來處理妻顶,Nodejs中有大量的模塊可以幫助開發(fā)人員來完成這些操作,接下來將會(huì)以Express為例來詳細(xì)講解蜒车。