Node.js介紹
Node.js
是一種新興的服務器語言,用Javascript
開發(fā)服務器。-
Node.js
本質(zhì)上是對Google的V8引擎進行了封裝,并且內(nèi)置了一個http
模塊- 傳統(tǒng)意義上的 JavaScript 運行在瀏覽器上,這是因為瀏覽器內(nèi)核實際上分為兩個部分: 渲染引擎 和 JavaScript 引擎。前者負責渲染 HTML + CSS,后者負責解析JavaScript。
編譯型語言要 編寫-編譯-鏈接-運行,腳本語言的代碼即是最終的執(zhí)行文件,相當于把編譯型語言的編譯鏈接過程改為解析了
解釋型語言執(zhí)行效率較低,且不能脫離解釋器運行,但它的跨平臺型比較容易,只需提供特定解釋器(引擎)即可
引擎:一種能夠快速解析Javascript的內(nèi)核
內(nèi)核:軟件與硬件之間進行通訊的API
Web服務器: 可以處理HTTP請求的服務器
Node.js工作原理與優(yōu)缺點(了解一門語言的開始)
傳統(tǒng)Web服務器原理 :
每新增一個連接(請求)便生成一個新的線程,這個新的線程會占用系統(tǒng)內(nèi)存,最終會占掉所有的內(nèi)存
Node.js搭建的服務器工作原理:
無論增加多少個連接(請求),所有請求都運行在一個線程中。使用非阻塞的異步 I/O 調(diào)用
Node.js服務器優(yōu)點:
Node.js服務器很大程度減少了內(nèi)存消耗
Node.js服務器缺點:
大量的請求可能會導致單線程暫時失去反應,并導致所有的其他客戶端的請求阻塞,計算結(jié)束才恢復正常
Node.js的使用
- Node.js 用模塊(Module)來劃分不同的功能(可以簡化開發(fā)),模塊就是框架就是庫,一個框架一個功能(與組件化類似)
1.使用http模塊搭建web服務器
// 1.加載http模塊
var http = require('http');
// 2.創(chuàng)建http服務器
// 服務器被訪問的時候,就會自動調(diào)用回調(diào)函數(shù)
// 默認訪問跟路徑
var server = http.createServer(function (request,response) {
response.write('hello'); // 響應
})
// 3.綁定端口
server.listen(3000);
2.Express框架(庫,模塊)
- Express建立在Node.js內(nèi)置的http框架上,可以快速地搭建Web服務器
2.1.express監(jiān)聽請求
// 導入express
var express = require('express');
// 創(chuàng)建服務器
var server = express();
// 監(jiān)聽get請求
server.get('/home',function (request,response) { // 第一個參數(shù):請求路徑
response.send('Hello')
});
// 監(jiān)聽post請求
server.post('/home',function (request,response) {
console.log('有人訪問服務器')
response.send('Hello,Post')
});
// 綁定端口
server.listen(3000);
2.2.express路由
- 路由: 不同的訪問路徑
- 訪問地址
/home
應該往端口后拼接,如8080/home
- 路由句柄(索引): 執(zhí)行完一個函數(shù),接著執(zhí)行下一個
- 有時候處理一個請求需要做很多其他事情,可以區(qū)分開不同的業(yè)務邏輯
- 一定要調(diào)用
next()
才會進行下面操作
// 導入express
var express = require('express');
// 創(chuàng)建服務器
var server = express();
// 路由句柄
server.get('/home',function (request,response ,next) {
console.log('去數(shù)據(jù)庫獲取數(shù)據(jù)') // 1.去數(shù)據(jù)庫獲取數(shù)據(jù)
next(); // 一定不能少
}, function (request,response) {
console.log('2.發(fā)送響應給客戶端') // 2.發(fā)送響應給客戶端
});
// 綁定端口
server.listen(3000);
2.3.express中間件:use
- 不能放在請求回調(diào)函數(shù)中,要在請求完成之前調(diào)用
- 一定要調(diào)用
next()
才會進行下面操作 - 原理:發(fā)送一個請求給服務器的時候,會被中間件攔截,自動執(zhí)行中間件的回調(diào)函數(shù)
// 導入express
var express = require('express');
// 創(chuàng)建服務器
var server = express();
// 中間件
server.use('/home',function (request,response,next) {
console.log('去數(shù)據(jù)庫獲取數(shù)據(jù)')
next();
});
server.get('/home',function (request,response ,next) {
console.log('發(fā)送響應給客戶端')
});
// 綁定端口
server.listen(3000);
2.4.express獲取get請求參數(shù)
-
request.query
會把請求參數(shù)包裝成字典對象
var express = require('express');
var server = express();
server.get('/home',function (request,response) {
// 獲取get請求參數(shù)
response.send(request.query)
});
server.listen(5000);
2.5.express獲取post請求參數(shù)
- 發(fā)送http請求時,需要設(shè)置
content-type
字段
1.application/x-www-form-urlencoded // 普通請求,默認
2.application/json // json格式的參數(shù),比如參數(shù)是字典或者數(shù)組
2.3 multipart/form-data // 傳輸文件,文件上傳
AFN框架中
AFHTTPRequestSerializer
使用的是application/x-www-form-urlencoded
,AFJSONRequestSerializer
使用的是application/json
-
Node.js需要用
body-parser
模塊解析post請求參數(shù)
安裝body-parser模塊用命令行: npm install body-parser
-
bodyParser.urlencoded({extended:true})
就是解析 application/x-www-form-urlencoded 類型參數(shù)-
bodyParser.urlencoded
的參數(shù)是字典,要用 {}
extends是必傳參數(shù),表示是否展開
-
-
bodyParser.json()
就是解析 json 類型參數(shù)
-
var express = require('express');
var server = express();
// 引入bodyParser模塊
var bodyParser = require('body-parser');
// 解析 application/x-www-form-urlencoded 類型參數(shù),把參數(shù)轉(zhuǎn)換成對象,放入request.body中
var urlencodedParser = bodyParser.urlencoded({extended:true});
// 解析 json 類型參數(shù),把參數(shù)轉(zhuǎn)換成對象,放入request.body中
// var jsonParser = bodyParser.json();
// 使用中間件攔截,參數(shù)放入request的body中
server.use(urlencodedParser);
// 監(jiān)聽post請求
server.post('/home',function(request,response){
console.log(request.body);
response.send(request.body);
});
server.listen(8080);
2.6.express創(chuàng)建對象返回給客戶端
- 創(chuàng)建字典:
{}
- 創(chuàng)建數(shù)組:
[]
-
function
:可以定義函數(shù)和對象(一般有屬性的都是對象) -
this
表示當前對象,類似self - 創(chuàng)建對象用
new
- 對象可以直接輸出,自動轉(zhuǎn)換為json字典
var express = require('express');
var server = express();
var room = ['1','2','3'];
// 定義方法
function log(){
console.log('定義函數(shù)');
}
// 定義對象
function User(name,age){
// 定義屬性,并且賦值
this.name = name;
// 定義屬性,并且賦值
this.age = age;
// 定義方法
this.log = function(){
console.log(this.name + this.age);
}
}
// 創(chuàng)建對象
var u = new User('王思聰',18);
u.log();
server.get('/room',function(request,response){
// 輸出對象
console.log(u);
response.send(u);
});
server.listen(8080);
3.模塊化開發(fā)
- 如果把所有代碼寫在一個文件中,不好維護,代碼可讀性不好
-
exports
,module.exports
用來定義模塊接口 - 定義函數(shù):
exports
- 定義對象:
module.exports
-
module.exports
和exports
不能重復,重復以module.exports
為準 -
./ :
表示當前文件
// main.js:
var express = require('express');
var server = express();
// 引入user模塊
var User = require('./User');
var user = new User('x','20');
// 監(jiān)聽post請求
server.get('/room',function(request,response){
response.send(user);
});
server.listen(8080);
// User.js:
// exports.log = function(){
// console.log("引入其他模塊");
// }
function User(name,age){
this.name = name;
this.age = age;
}
module.exports = User;
4.字典和數(shù)組的刪除操作
- 刪除可以用
splice
,delete
-
splice
的第一個參數(shù)表示刪除位置的開始,第二個參數(shù)白哦是刪除幾個元素 -
delete
只是把元素刪除,當前角標位置并不會移除
-
var express = require('express');
var server = express();
var arr = [1,2,3];
// 刪除
delete arr[0];
arr.splice(0,1);
server.listen(8080);
var express = require('express');
var server = express();
var arr = {'a':'1','b':'2'};
delete arr['a'];
server.listen(8080);
為什么Node.js這個服務器語言不需要搭建Apache等服務器?
因為Node.js是基于V8去封裝的,所以在下載Node.js的時候,就會自帶V8。
Node.js和PHP類似都是腳本語言,需要內(nèi)核才能跑起來。Node.js依賴V8,PHP依賴Apache。
比如OC就需要依賴iPhone手機內(nèi)核才能跑起來。
Node.js內(nèi)置了 http
模塊,可以輕而易舉的實現(xiàn)網(wǎng)站和服務器的組合。不像PHP必須自己搭建一個Apache之類的HTTP服務器,然后通過服務器的模塊加載CGI,才能將PHP腳本的執(zhí)行結(jié)果呈現(xiàn)給用戶
Node.js是單線程的。單線程怎么開啟異步工作?
傳統(tǒng)的服務器多是基于 線程模型 的。啟動后開始等待接受連接。當收到一個連接,服務器保持連通,直到請求完成。如果他需要花幾微妙時間去讀取磁盤或者訪問數(shù)據(jù)庫,服務器就阻塞了IO操作(阻塞式IO)。想提高性能就只有啟動更多的線程。
Node.js服務器是基于 事件驅(qū)動模型 (與iOS的Runloop類似)的。當服務器接接收到請求A,把請求A放入事件隊列,去服務下一個請求B,當請求B處理完,從事件隊列中取出A,進行處理。服務器一直接受請求而不等待任何讀寫操作。(非阻塞式IO或者事件驅(qū)動IO)
多線程與單線程:
不管是多線程還是單線程,計算機一次最多執(zhí)行一個任務,因為CPU就一個,只有它才能運行任務。
多線程與單線程的區(qū)別主要在于有序和無序:單線程必須一個一個按順序執(zhí)行,多線程可以在多條線程存放任務,而且CPU不確定先執(zhí)行哪個任務,隨機執(zhí)行
參考資料
搭建Web服務器