nodejs核心技術

1、知識結構:

http模塊:配置簡單 的web服務,npm/cnpm工具javascript

express框架:express中間件進行服務配置;路由;請求處理;html

DB服務:學習使用mysql關係型數據庫;java

web接口服務:使用express、koa簡單配置接口服務、JSON解析;node

nodejs RESTful API:提供跨語言、跨平臺的服務接口、支持web/appmysql

node文件系統:服務端基本的文件讀寫操做nginx


2、Node.js簡介:

Node.js是一個讓JavaScript運行在服務器端的開發平臺,它讓JavaScript的觸角伸到了服務器端。但Node.js彷佛與其它服務器端語言有點不一樣:web

Node.js不是一種獨立的語言,與PHP、Python等「既是語言,又是平臺」不一樣,Node.js使用的是JavaScript進行編程,Node.js是一個工具,語言還是JavaScript。sql

與PHP、JSP等相比,Node.js跳過了apache、tomcat、nginx、iis等http服務器,它本身不用創建在任何服務器軟件之上。數據庫

Node.js哲學:花最小的硬件成本,追求更高的併發,更高的處理性能。express

Node採用一系列「非阻塞」庫來支持事件循環的方式。本質上就是爲文件系統、數據庫之類的資源提供接口。向文件系統發送一個請求時,無需等待硬盤(尋址並檢索文件),硬盤準備好的時候非阻塞接口會通知Node。該模型以可擴展的方式簡化了對慢資源的訪問, 直觀,易懂。尤爲是對於熟悉onmouseover、onclick等DOM事件的用戶,更有一種似曾相識的感受。

Node.js特色:

單線程:

說明Node.js是單線程的一個實例 :

var http = require('http'); var a = 0; http.createServer(function (request, response) { a++; // 發送 HTTP 頭部 // HTTP 狀態值: 200 : OK // 內容類型: text/plain response.writeHead(200, {'Content-Type': 'text/plain'}); // 發送響應數據 "Hello World" response.end(a.toString()); }).listen(8888); // 終端打印以下信息 console.log('Server running at http://127.0.0.1:8888/');

Node.js的優勢:

Node.js能夠在不新增額外線程的狀況下,依然能夠對任務進行併發處理 —— Node.js是單線程的。它經過事件循環(event loop)來實現併發操做,對此,咱們應該要充分利用這一點 —— 儘量的避免阻塞操做,取而代之,多使用非阻塞操做。

事件驅動:

異步回調:至關於一個服務員照顧多個顧客

說明實例:當有多個用戶同時訪問的時候,會出現同一個用戶進來和讀取完畢不連續的狀況

//建立服務器用的 var http = require('http'); //讀取文件用的 var fs = require('fs'); http.createServer(function (req, res) { //ip地址 var ip = req.connection.remoteAddress; console.log(ip + "來了,開始讀取文件!"); //來客人以後的事情,要去讀取一個文本文件 fs.readFile('./input.txt', function(err, filecontent){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(filecontent); //提示 console.log(ip + "讀取文件完畢!"); }); }).listen(8888); // 終端打印以下信息 console.log('Server running at http://127.0.0.1:8888/');

只要I/O越多,Node.js宏觀上越並行;但運算越多,Node.js宏觀上越不併行,此時網頁打開速度嚴重變慢,由於計算過程當中CPU只能爲某一用戶服務,難以脫身,因此Node.js線程就被這一用戶霸佔了。

所以Node.js適合開發I/O多的業務,而不適合計算任務繁重的業務。

非阻塞I/O:

例如:當訪問數據庫取得數據的時候,須要一段較長的時間,在傳統的處理機制中,在執行了訪問數據庫代碼以後,整個線程都將暫停下來等待數據庫返回結果才能執行後面的代碼,也就是說I/O阻塞了後面代碼的執行,極大的下降了程序的執行效率。

因爲Node.js採用了非阻塞I/O機制,所以在執行了訪問數據庫的代碼以後,將當即轉而執行其後面的代碼,將數據庫返回結果的處理代碼放在回調函數中,從而提升了程序的執行效率。

當某個I/O執行完畢時,將以事件的形式通知執行I/O操做的線程,線程執行這個事件的回調函數。爲了處理異步I/O,線程必須有事件循環,不斷的檢查有沒有未處理的事件,依次予以處理。

var fs = require('fs'); fs.readFile("./input.txt", "utf8", function(err, data) { console.log(data); }); var waitTill = new Date(new Date().getTime() + 2 * 1000); while (waitTill > new Date()) {} console.log("finished"); //如上所示,若是代碼中有同步執行的代碼,無論這個同步執行的代碼須要執行多久,它前面的異步代碼老是在最後才執行

 在阻塞模式下,一個線程只能處理一項任務,要想提升吞吐量必須經過多線程。而非阻塞模式下,一個線程永遠在執行計算操做,這個線程的核心利用率永遠是100%,因此這個是一個特別有哲理的解決方案:與其人多,但好多人閒着,還不如一我的玩命,往死裏幹活。

Node..js適合開發的業務:

當業務程序須要處理大量併發的I/O,而在向客戶端發出響應以前,應用程序內部並不須要進行很是複雜的處理的時候,Node..js很是合適。Node..js也很是適合和websocket配合,開發長鏈接的實時交互應用程序,好比:用戶表單收集、考試系統、聊天室、圖文直播、提供JSON的API(爲MVVM框架使用)。


3、命令行窗口(cmd窗口/終端):

一、經常使用的命令:

dir:列出當前文件夾下的全部文件;

cd 目錄名:進入到指定的目錄;

md 目錄名:建立一個指定的文件夾;

rd 目錄名:刪除一個指定的文件夾;

二、目錄:

.:表示當前目錄;

..:表示上一級目錄;

三、環境變量:

path:當咱們在命令行窗口打開一個文件或調用一個程序時系統會首先在當前目錄下尋找程序,若是找到了則直接打開,若是沒有找到則會依次到環境變量path的路徑中尋找,直到找到爲止,若是沒有找到則會報錯。

四、快速進入指定文件夾的方法:

在指定文件夾的地址欄中輸入:cmd


4、進程和線程:

進程:負責爲程序的運行提供必備的環境,至關於工廠中的車間;

線程:計算機中最小的計算單元,負責執行進程中的程序,至關於工廠中的工人。


5、node執行js文件:

cmd中進入hello.js所在文件夾,cmd中輸入:

node hello.js

6、node整合WebStorm:

WebStorm菜單的File->Settings:搜索node,找到Node.js and NPM,在右側的Node interpreter中輸入node.exe所在位置便可。


7、WebStorm中node代碼提示:

WebStorm菜單的File->Settings:搜索node,找到Node.js and NPM,在右側的Coding Assistance中啓用便可。


8、模塊化:

在Node中,一個js文件就是一個模塊;

在 Node中,每個js文件的js代碼都是獨立運行在一個函數中,好比:

console.log("我是模塊01.moudle.js!"); var x = 20; var y = 30;

實際上是:

function(){ console.log("我是模塊01.moudle.js!"); var x = 20; var y = 30; } 

而不是全局做用域,因此一個模塊中的變量和函數在其它模塊中沒法訪問 。

在Node中,經過require()函數來引入外部模塊,require()中能夠傳遞一個文件的路徑做爲參數,node將會自動根據該路徑來引入外部模塊,這裏路徑若是使用相對路徑,則必須以「.」或者「..」開頭;

咱們能夠經過exports來向外部暴露變量或者方法,只須要將須要暴露給外部的變量或者方法設置爲exprots的屬性便可。

console.log("我是模塊01.moudle.js!"); exports.x = 20; exports.y = 30; exports.fn = function(){ console.log("我是模塊01.moudle.js中的一個函數!"); }

使用require()引入模塊之後,該函數會返回一個對象,這個對象表明的是引入的模塊。

咱們使用require()引入外部模塊時,使用的就是模塊標識。

模塊分紅兩大類:

核心模塊:由node引擎提供的模塊,核心模塊的標識就是模塊的名字;

文件模塊:用戶自定義的模塊,文件模塊的標識就是文件的路徑。

node模塊中用var定義的變量都是局部變量,取消掉var時定義的變量纔是所有變量:

a = 10; console.log(global.a);//global是node中的一個全局對象,它的做用和網頁中的window相似,在全局中建立的變量都會用global的屬性保存,在全局中建立的函數都會做爲global的方法保存
var a = 10;
console.log(arguments);
var a = 10; console.log(arguments.callee + "");//arguments.callee保存的是當前執行的函數對象

輸出:

function (exports, require, module, __filename, __dirname) { var a = 10; console.log(arguments.callee + "");//arguments.callee保存的是當前執行的函數對象 }

由此可知:

當node在執行模塊中的代碼時,它首先會在代碼的最頂部添加以下代碼:

function (exports, require, module, __filename, __dirname) {

在代碼的最底部,添加以下代碼:

}

實際上,模塊中的代碼都是包裝在一個函數中執行的,而且在函數執行時,同時傳遞了5個實參:

exports:該對象用來將對象或者函數暴露到外部,

require:函數,用來引入外部的模塊,

module:用來表明的是當前模塊自己,exports就是模塊的屬性。既能夠用exports導出,也能夠用module.exports導出二者指向的是同一個對象,

__filename:當前模塊的完整路徑,

__dirname:當前模塊所在文件夾的完整路徑


9、exports與modules.exports的區別:

本質上二者是相等的,可是exports只能經過「.」的方式向外暴露內部變量,而modules.exports既能夠經過「.」的形式,也能夠直接賦值;

exports.name = '孫悟空';
exports.from = "西遊記"
module.exports = { name: '孫悟空', from: "西遊記", sayName: function(){ console.log(this.name); } }

10、包簡介:

CommonJS的包規範容許咱們將相關的模塊組合在一塊兒,造成一組完整的工具。

CommonJS的包規範包括包結構和包描述文件。

包結構:

package.json:必須

bin:可執行的二進制文件,非必須

lib:js文件,非必須;

doc:文檔,非必須;

test:單元測試,非必須

包描述文件:

用於表達非代碼相關的信息,它是一個json文件-package.json,位於包的根目錄下,是包的重要組成部分。


11、npm(Node package manager)簡介:

至關於360安全衛士裏的軟件管家。

對於node而言,npm幫助其完成了第三方模塊的發佈、安裝和依賴等。藉助npm,node與第三方模塊之間造成了很好的一個生態系統。

npm -v:查看npm版本;

npm version: 查看全部模塊的版本;

npm search 包名:搜索包;

npm install/i 包名 :安裝包;

npm remove/r 包名:刪除包;

npm remove/r 包名 --save:將包名在依賴中刪除(node _modules中不刪除);

npm install 包名 --save:安裝包並添加到依賴中(package.json的dependencies中);

npm install:下載當前項目所依賴的包(package.json的dependencies中的包);

npm install 包名 -g:全局安裝包(全局安裝的包通常是一些工具)


12、node模塊引用:

經過npm下載的包都放到node_modules中,咱們經過npm下載的包直接經過包名引用便可。

node在經過模塊名字來引用模塊時它會首先在當前目錄的node_modules中尋找是否含有該模塊,若是有則直接使用,若是沒有則直接去上一級目錄的node_modules中尋找,若是有則直接使用,若是沒有,則繼續再去上一級目錄中尋找,直到找到磁盤的根目錄,若是依然沒有,則直接報錯。


十3、EventEmitter:

Node.js 全部的異步 I/O 操做在完成時都會發送一個事件到事件隊列。

Node.js 裏面的許多對象都會分發事件:一個 net.Server 對象會在每次有新鏈接時觸發一個事件, 一個 fs.readStream 對象會在文件被打開的時候觸發一個事件。 全部這些產生事件的對象都是 events.EventEmitter 的實例。

events 模塊只提供了一個對象: events.EventEmitter。EventEmitter 的核心就是事件觸發與事件監聽器功能的封裝。

你能夠經過require("events");來訪問該模塊。

// 引入 events 模塊 var events = require('events'); // 建立 eventEmitter 對象 var eventEmitter = new events.EventEmitter();

EventEmitter 對象若是在實例化時發生錯誤,會觸發 error 事件。當添加新的監聽器時,newListener 事件會觸發,當監聽器被移除時,removeListener 事件被觸發。

下面咱們用一個簡單的例子說明 EventEmitter 的用法:

//event.js 文件 var EventEmitter = require('events').EventEmitter; var event = new EventEmitter(); event.on('some_event', function() { console.log('some_event 事件觸發'); }); setTimeout(function() { event.emit('some_event'); }, 1000); 

執行結果以下:

運行這段代碼,1 秒後控制檯輸出了 'some_event 事件觸發'。其原理是 event 對象註冊了事件 some_event 的一個監聽器,而後咱們經過 setTimeout 在 1000 毫秒之後向 event 對象發送事件 some_event,此時會調用some_event 的監聽器。

$ node event.js 
some_event 事件觸發

EventEmitter 的每一個事件由一個事件名和若干個參數組成,事件名是一個字符串,一般表達必定的語義。對於每一個事件,EventEmitter 支持 若干個事件監聽器。

當事件觸發時,註冊到這個事件的事件監聽器被依次調用,事件參數做爲回調函數參數傳遞。

讓咱們如下面的例子解釋這個過程:

//event.js 文件
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 參數', 'arg2 參數');

執行以上代碼,運行的結果以下:

$ node event.js 
listener1 arg1 參數 arg2 參數
listener2 arg1 參數 arg2 參數

 以上例子中,emitter 爲事件 someEvent 註冊了兩個事件監聽器,而後觸發了 someEvent 事件。

運行結果中能夠看到兩個事件監聽器回調函數被前後調用。 這就是EventEmitter最簡單的用法。

EventEmitter 提供了多個屬性,如 on 和 emit。on 函數用於綁定事件函數,emit 屬性用於觸發一個事件。接下來咱們來具體看下 EventEmitter 的屬性介紹。

方法

序號 方法 & 描述
1 addListener(event, listener)
爲指定事件添加一個監聽器到監聽器數組的尾部。
2 on(event, listener)
爲指定事件註冊一個監聽器,接受一個字符串 event 和一個回調函數。
server.on('connection', function (stream) {
console.log('someone connected!');
});
3 once(event, listener)
爲指定事件註冊一個單次監聽器,即 監聽器最多隻會觸發一次,觸發後馬上解除該監聽器。
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
});
4 removeListener(event, listener)

移除指定事件的某個監聽器,監聽器必須是該事件已經註冊過的監聽器。

它接受兩個參數,第一個是事件名稱,第二個是回調函數名稱。

var callback = function(stream) {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
5 removeAllListeners([event])
移除全部事件的全部監聽器, 若是指定事件,則移除指定事件的全部監聽器。
6 setMaxListeners(n)
默認狀況下, EventEmitters 若是你添加的監聽器超過 10 個就會輸出警告信息。 setMaxListeners 函數用於提升監聽器的默認限制的數量。
7 listeners(event)
返回指定事件的監聽器數組。
8 emit(event, [arg1], [arg2], [...])
按參數的順序執行每一個監聽器,若是事件有註冊監聽返回 true,不然返回 false。

類方法

序號 方法 & 描述
1 listenerCount(emitter, event)
返回指定事件的監聽器數量。
events.EventEmitter.listenerCount(emitter, eventName) //已廢棄,不推薦
events.emitter.listenerCount(eventName) //推薦

 事件

序號 事件 & 描述
1 newListener
  • event - 字符串,事件名稱

  • listener - 處理事件函數

該事件在添加新監聽器時被觸發。

2 removeListener
  • event - 字符串,事件名稱

  • listener - 處理事件函數

從指定監聽器數組中刪除一個監聽器。須要注意的是,此操做將會改變處於被刪監聽器以後的那些監聽器的索引。

實例

如下實例經過 connection(鏈接)事件演示了 EventEmitter 類的應用。

建立 main.js 文件,代碼以下:

var events = require('events'); var eventEmitter = new events.EventEmitter(); // 監聽器 #1 var listener1 = function listener1() { console.log('監聽器 listener1 執行。'); } // 監聽器 #2 var listener2 = function listener2() { console.log('監聽器 listener2 執行。'); } // 綁定 connection 事件,處理函數爲 listener1 eventEmitter.addListener('connection', listener1); // 綁定 connection 事件,處理函數爲 listener2 eventEmitter.on('connection', listener2); var eventListeners = eventEmitter.listenerCount('connection'); console.log(eventListeners + " 個監聽器監聽鏈接事件。"); // 處理 connection 事件 eventEmitter.emit('connection'); // 移除監綁定的 listener1 函數 eventEmitter.removeListener('connection', listener1); console.log("listener1 再也不受監聽。"); // 觸發鏈接事件 eventEmitter.emit('connection'); eventListeners = eventEmitter.listenerCount('connection'); console.log(eventListeners + " 個監聽器監聽鏈接事件。"); console.log("程序執行完畢。");

以上代碼,執行結果以下所示:

$ node main.js
2 個監聽器監聽鏈接事件。
監聽器 listener1 執行。
監聽器 listener2 執行。
listener1 再也不受監聽。
監聽器 listener2 執行。
1 個監聽器監聽鏈接事件。
程序執行完畢。

 


 十4、使用 GET 或 POST 請求發送數據:

server.js

var http = require('http'); var fs = require('fs'); var url = require('url'); var querystring = require('querystring'); function startServer(route, handle) { var onRequest = function(request, response) { var pathname = url.parse(request.url).pathname; console.log('Request received ' + pathname); var data = []; request.on("error", function(err) { console.error(err); }).on("data", function(chunk) { data.push(chunk); }).on('end', function() { if (request.method === "POST") { if (data.length > 1e6) { request.connection.destroy(); } data = Buffer.concat(data).toString(); route(handle, pathname, response, querystring.parse(data)); } else { var params = url.parse(request.url, true).query; route(handle, pathname, response, params); } }); } var server = http.createServer(onRequest); server.listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000'); } module.exports.startServer = startServer;

handler.js

var fs = require('fs'); function home(response) { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(response); } function review(response) { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(response); } function api_records(response, params) { response.writeHead(200, { 'Content-Type': 'application/json' }); response.end(JSON.stringify(params)); } module.exports = { home: home, review: review, api_records: api_records }

 index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>hfpp2012</title> </head> <body> <form action="/api/v1/records" method="post"> name: <input type="text" name="name" /> age: <input type="text" name="age" /> <input type="submit" value="Submit"> </form> </body> </html>

十5、經常使用工具:

var events = require('events'); var util = require('util'); var Person = function(name) { this.name = name } util.inherits(Person, events.EventEmitter); var xiaoming = new Person('xiaoming'); var lili = new Person('lili'); var lucy = new Person('lucy'); var person = [xiaoming, lili, lucy]; person.forEach(function(person) { person.on('speak', function(message) { console.log(person.name + " said: " + message); }) }) xiaoming.emit('speak', 'hi'); lucy.emit('speak', 'I want a curry'); // var myEmitter = new events.EventEmitter(); // myEmitter.on('someEvent', function(message) { // console.log(message); // }) // myEmitter.emit('someEvent', 'the event was emitted');

十6、Buffer緩存區:

Buffer的結構和數組很像,操做的方法也和數組相似;

數組中不能存儲二進制的文件,而Buffer就是專門用來存儲二進制數據;

爲何要用Buffer?Node.js其實就作兩件事,一是接收請求,另外一個是發送請求,請求都是以二進制的方式傳遞的,接收之後或者發送以前二進制數據都是放在緩存中。

使用Buffer不須要引用模塊,直接使用便可;

在Buffer中存儲的是二進制數據,但在顯示時是以十六進制的形式顯示;存入時的數字能夠是任何進制,但在控制檯或者頁面就是必定只能以十進制輸出顯示,若是存儲的是字符的話能夠用其它進制顯示,方式str.toString(x);

var str = "Hello Atguigu"; var buf = Buffer.from(str); console.log(buf);//<Buffer 48 65 6c 6c 6f 20 41 74 67 75 69 67 75> var buff = Buffer.alloc(10); buff[0] = 123; console.log(buff[0]);//123 console.log(buff[0].toString(2));//1111011 buff[1] = 0xaa; console.log(buff[1]);//170 console.log(buff[1].toString(16));//aa

Buffer中每個元素的範圍是00-ff(16進制) <=> 0-255(10進制) <=> 00000000-11111111(2進制);

計算機中1個0或者1個1咱們稱之爲1位(bit),計算機中數據是以字節爲單位傳輸的;

8bit=1byte(1字節);

1024byte=1kb;

1024kb=1mb;

1024mb=1gb;

1024gb=1tb;

Buffer中的1個元素佔用內存的1個字節;

Buffer的大小一旦肯定,則不能修改,Buffer其實是對底層內存的直接操做;

var str = "Hello Atguigu"; var buf = Buffer.from(str); console.log(buf); console.log(buf.length);//13,佔用內從大小 console.log(str.length);//13,字符長度 var str2 = "Hello 尚硅谷"; var buf2 = Buffer.from(str2); console.log(buf2); console.log(buf2.length);//15,佔用內從大小,1個漢字佔用3個字節 console.log(str2.length);//9,字符長度
Buffer.from(str)//將一個字符串轉換爲Buffer Buffer.alloc(size)//建立一個指定大小的Buffer Buffer.allocUnsafe(size)//建立一個指定大小的Buffer,可是可能包含敏感數據 buf.toString()//將緩存區中的數據轉換爲字符串

 十7、路由:

server.js

var http = require('http'); var fs = require('fs'); function startServer() { var onRequest = function(request, response) { console.log('Request received ' + request.url); if (request.url === '/' || request.url === '/home') { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(response); } else if (request.url === '/review') { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(response); } else if (request.url === '/api/v1/records') { response.writeHead(200, { 'Content-Type': 'application/json' }); var jsonObj = { name: "hfpp2012" }; response.end(JSON.stringify(jsonObj)); } else { response.writeHead(404, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(response); } } var server = http.createServer(onRequest); server.listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000'); } exports.startServer = startServer;

review.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> review page </body> </html>

 404.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> 404 error page </body> </html>

重構路由代碼:
app.js

var server = require('./server'); var router = require('./router'); var handler = require('./handler'); var handle = {}; handle["/"] = handler.home; handle['/home'] = handler.home; handle['/review'] = handler.review; handle['/api/v1/records'] = handler.api_records; server.startServer(router.route, handle);

server.js

var http = require('http'); var fs = require('fs'); function startServer(route, handle) { var onRequest = function(request, response) { console.log('Request received ' + request.url); route(handle, request.url, response); } var server = http.createServer(onRequest); server.listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000'); } module.exports.startServer = startServer;

 router.js

var fs = require('fs'); function route(handle, pathname, response) { console.log('Routing a request for ' + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response); } else { response.writeHead(404, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(response); } } module.exports.route = route;

handler.js

var fs = require('fs'); function home(response) { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(response); } function review(response) { response.writeHead(200, { 'Content-Type': 'text/html' }); fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(response); } function api_records(response) { response.writeHead(200, { 'Content-Type': 'application/json' }); var jsonObj = { name: "hfpp2012" }; response.end(JSON.stringify(jsonObj)); } module.exports = { home: home, review: review, api_records: api_records }

 十8、文件系統(fs):

文件系統簡單來講就是經過Node.js來操做系統中的文件;

使用文件系統首先須要引入fs模塊,fs是核心模塊,直接引入不須要下載;

文件的寫入步驟:

手動步驟:

a、打開文件;

b、向文件中寫入內容;

c、保存並關閉文件;

一、同步寫入文件:

var fs = require('fs'); var fd = fs.openSync('./input.txt', 'w'); fs.writeSync(fd, '今每天氣真不錯!'); fs.closeSync(fd);

二、異步寫入文件:

var fs = require('fs'); //打開文件 fs.open('./input.txt', 'w', function(err, fd){ if(!err){ //寫入文件 fs.write(fd, '這是異步寫入的內容!', function(err){ if(!err){ console.log('寫入成功!!!'); }else{ console.log(err); } //關閉文件 fs.close(fd, function(err){ if(!err){ console.log("文件已經關閉!"); } }); }); }else{ console.log(err); } });

三、簡單文件寫入(不須要打開文件):

var fs = require('fs'); fs.writeFile('./input.txt', '這是經過writeFile寫入的內容', function(err){ if(!err){ console.log(); } });
Flag 描述
r 以讀取模式打開文件。若是文件不存在拋出異常。
r+ 以讀寫模式打開文件。若是文件不存在拋出異常。
rs 以同步的方式讀取文件。
rs+ 以同步的方式讀取和寫入文件。
w 以寫入模式打開文件,若是文件不存在則建立。
wx 相似 'w',可是若是文件路徑存在,則文件寫入失敗。
w+ 以讀寫模式打開文件,若是文件不存在則建立。
wx+ 相似 'w+', 可是若是文件路徑存在,則文件讀寫失敗。
a 以追加模式打開文件,若是文件不存在則建立。
ax 相似 'a', 可是若是文件路徑存在,則文件追加失敗。
a+ 以讀取追加模式打開文件,若是文件不存在則建立。
ax+ 相似 'a+', 可是若是文件路徑存在,則文件讀取追加失敗。

四、使用絕對路徑寫入文件:

var fs = require('fs'); //或者C:/Users/Administrator/Desktop/input.txt fs.writeFile('C:\\Users\\Administrator\\Desktop\\input.txt', '這是經過writeFile寫入的內容', {flag: 'a'}, function(err){ if(!err){ console.log(); } });

五、流式文件寫入:

同步、異步、簡單文件的寫入都不太適合大文件的寫入,性能較差,容易致使內存溢出。

var fs = require('fs'); var ws = fs.createWriteStream('./input.txt', ); ws.once('open', function(){ console.log('流打開了~~~'); }); ws.once('close', function(){ console.log('流關閉了~~~'); }); ws.write('經過可寫流寫入的內容'); ws.write('鋤禾日當午,'); ws.write('汗滴禾下土,'); ws.write('誰知盤中餐,'); ws.write('粒粒皆辛苦!'); ws.end();

五、簡單文件讀取:

var fs = require('fs'); fs.readFile('H:\\個人圖片\\0064wDqKgy1fujq6czvkij30j60nz0uu.jpg', function(err, data){ if(!err){ //console.log(data.toString());//由於讀取到的可能不止文本文件,因此返回的是二進制 fs.writeFile('./hello.jpg', data, function(err){ if(!err){ console.log('文件 寫入成功'); } }); } });

六、流式文件讀取:

/* 流式文件讀取也適用於一些比較大的文件,能夠分屢次將文件讀取到內存中 */ var fs = require("fs"); //建立一個可讀流 var rs = fs.createReadStream("C:/Users/lilichao/Desktop/筆記.mp3"); //建立一個可寫流 var ws = fs.createWriteStream("a.mp3"); //監聽流的開啓和關閉 rs.once("open",function () { console.log("可讀流打開了~~"); }); rs.once("close",function () { console.log("可讀流關閉了~~"); //數據讀取完畢,關閉可寫流 ws.end(); }); ws.once("open",function () { console.log("可寫流打開了~~"); }); ws.once("close",function () { console.log("可寫流關閉了~~"); }); //若是要讀取一個可讀流中的數據,必需要爲可讀流綁定一個data事件,data事件綁定完畢,它會自動開始讀取數據 rs.on("data", function (data) { //console.log(data); //將讀取到的數據寫入到可寫流中 ws.write(data); }); 
//流式文件讀取通常適用於比較大的文件,能夠分屢次將文件讀取到內存中 var fs = require('fs'); //建立一個可讀流 var rs = fs.createReadStream('H:\\個人圖片\\0064wDqKgy1fujq6czvkij30j60nz0uu.jpg'); //建立一個可寫流 var ws = fs.createWriteStream('./node.jpg'); //監聽流的開啓和關閉 rs.once('open', function(){ console.log('可讀流打開了!'); }); rs.once('close', function(){ console.log('可讀流關閉了!'); }); //監聽流的開啓和關閉 ws.once('open', function(){ console.log('可寫流打開了!'); }); ws.once('close', function(){ console.log('可寫流關閉了!'); }); //pipe()可將可讀流中的內容直接輸出到可寫流 rs.pipe(ws);

七、fs其它操做:

• 驗證路徑是否存在

– fs.existsSync(path)

• 獲取文件信息

– fs.stat(path, callback)

– fs.statSync(path)

• 刪除文件

– fs.unlink(path, callback)

– fs.unlinkSync(path)

列出文件

– fs.readdir(path[, options], callback)

– fs.readdirSync(path[, options])

• 截斷文件

– fs.truncate(path, len, callback)

– fs.truncateSync(path, len)

• 創建目錄

– fs.mkdir(path[, mode], callback)

– fs.mkdirSync(path[, mode])

刪除目錄

– fs.rmdir(path, callback)

– fs.rmdirSync(path)

• 重命名文件和目錄

– fs.rename(oldPath, newPath, callback)

– fs.renameSync(oldPath, newPath)

• 監視文件更改寫入

– fs.watchFile(filename[, options], listener)


十9、WEB模塊(WEB服務器):

var http = require('http'); http.createServer(function(req, res){ console.log('Request received!'); res.writeHead(200, {'Content-Type' : 'text/plain'}); res.write('<html>'); res.write('<body>'); res.write('<h1>Hello, World!</h1>'); res.write('</body>'); res.write('</html>'); res.end(); }).listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000');

 響應 json:

var http = require('http'); http.createServer(function(req, res){ console.log('Request received!'); res.writeHead(200, { 'Content-Type': 'application/json' }); // response.write('Hello from out application'); var myObj = { name: "hfpp2012", job: "programmer", age: 27 }; res.end(JSON.stringify(myObj));//將json轉換爲字符串,便於傳輸;JSON.parse():反序列化,將轉換後的字符串轉換回json }).listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000');

響應HTML頁面 :

main.js:

var http = require('http'); var fs = require('fs'); http.createServer(function(req, res){ console.log('Request received'); res.writeHead(200, { 'Content-Type': 'text/html' }); var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8'); // res.write('Hello from out application'); myReadStream.pipe(res); }).listen(3000, '127.0.0.1'); console.log('Server started on localhost port 3000');

index.html:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>hfpp2012</title> </head> <body> hello wolrd </body> </html>

 二10、express框架:

一、什麼是express?

express是也一個基於node.js的極簡、靈活的web開發框架。能夠實現很是強大的web服務器功能。

二、express的特色:

能夠設置中間件響應或過濾http請求;

可使用路由實現動態網頁,響應不一樣的http請求;

內置支持ejs模板(默認是jade模板)實現模板渲染生成html;

三、express-generator生成器:

express-generator是express官方團隊爲開發者準備的一個快速生成工具,能夠很是快速的生成一個基本的express開發框架。

四、express安裝與使用:

1)安裝express-generator生成器;

cnpm i exrpess-generator

安裝完成後可使用express命令。

2)建立項目:

express -e 項目名稱 //自動建立項目名稱
express -e //手動建立項目名稱

3)安裝依賴:

cnpm i

4)開啓項目

node app
node start //自動查找當前目錄下的package.json文件,找到start對應的命令進行進行執行
node ./bin/www

5)測試項目:

打開瀏覽器輸入localhost


二11、Node.js 鏈接 MySQL:

安裝驅動:

cnpm install mysql

注意:cnpm install mysql是安裝nodejs的mysql模塊而不是安裝mysql數據庫,你的應用經過這個驅動程序鏈接並操做mysql中的庫和表。

若是你的電腦中沒有mysql,則請先安裝,相關教程以下:

https://jingyan.baidu.com/article/363872ec2e27076e4ba16fc3.html

在進行數據庫操做前,你須要將如下SQL 文件導入到你的 MySQL 數據庫中。

/* Navicat MySQL Data Transfer Source Server : 127.0.0.1 Source Server Version : 50621 Source Host : localhost Source Database : RUNOOB Target Server Version : 50621 File Encoding : utf-8 Date: 05/18/2016 11:44:07 AM */ SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `websites` -- ---------------------------- DROP TABLE IF EXISTS `websites`; CREATE TABLE `websites` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL DEFAULT '' COMMENT '絝欑偣鍚嶇О', `url` varchar(255) NOT NULL DEFAULT '', `alexa` int(11) NOT NULL DEFAULT '0' COMMENT 'Alexa 鎺掑悕', `country` char(10) NOT NULL DEFAULT '' COMMENT '鍥藉', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `websites` -- ---------------------------- BEGIN; INSERT INTO `websites` VALUES ('1', 'Google', 'https://www.google.cm/', '1', 'USA'), ('2', '娣樺疂', 'https://www.taobao.com/', '13', 'CN'), ('3', '鑿滈笩鏁欑▼', 'http://www.runoob.com/', '4689', 'CN'), ('4', '寰崥', 'http://weibo.com/', '20', 'CN'), ('5', 'Facebook', 'https://www.facebook.com/', '3', 'USA'); COMMIT; SET FOREIGN_KEY_CHECKS = 1; 

鏈接數據庫

var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', database : 'test' }); connection.connect(); connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results[0].solution); });

數據庫操做( CURD )

查詢數據

將上面咱們提供的 SQL 文件導入數據庫後,執行如下代碼便可查詢出數據:

var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var sql = 'SELECT * FROM websites'; //查 connection.query(sql,function (err, result) { if(err){ console.log('[SELECT ERROR] - ',err.message); return; } console.log('--------------------------SELECT----------------------------'); console.log(result); console.log('------------------------------------------------------------\n\n'); }); connection.end();

插入數據

var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)'; var addSqlParams = ['菜鳥工具', 'https://c.runoob.com','23453', 'CN']; //增 connection.query(addSql,addSqlParams,function (err, result) { if(err){ console.log('[INSERT ERROR] - ',err.message); return; } console.log('--------------------------INSERT----------------------------'); //console.log('INSERT ID:',result.insertId); console.log('INSERT ID:',result); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();

更新數據

var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var modSql = 'UPDATE websites SET name = ?,url = ? WHERE Id = ?'; var modSqlParams = ['菜鳥移動站', 'https://m.runoob.com',6]; //改 connection.query(modSql,modSqlParams,function (err, result) { if(err){ console.log('[UPDATE ERROR] - ',err.message); return; } console.log('--------------------------UPDATE----------------------------'); console.log('UPDATE affectedRows',result.affectedRows); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();

刪除數據

var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var delSql = 'DELETE FROM websites where id=6'; //刪 connection.query(delSql,function (err, result) { if(err){ console.log('[DELETE ERROR] - ',err.message); return; } console.log('--------------------------DELETE----------------------------'); console.log('DELETE affectedRows',result.affectedRows); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();

二12、其它工具:

nodemon:

npm install -g nodemon
相關文章
相關標籤/搜索