Node.js 知識(教程)

JavaScript on the Serverhtml

JavaScript was originally built for web browsers, but with Node.js we can use it on the server.前端

We can perform server-related tasks like file system access.node

 

歷史:

JavaScript是前端開發的惟一標準。git

2000年後開始的瀏覽器平臺大戰,致使了node的誕生。es6

在2009年,Ryan(人)正式推出了基於JavaScript語言和V8引擎的開源Web服務器項目,命名爲Node.js。github

選擇js,是由於它是單線程,只能使用異步IO。web

Node第一次把JavaScript帶入到後端服務器開發,加上世界上已經有無數的JavaScript開發人員,因此Node一會兒就火了起來。算法

 

在Node上運行的JavaScript相比其餘後端開發語言有何優點?

最大的優點是藉助JavaScript天生的事件驅動機制加V8高性能引擎,使編寫高性能Web服務垂手可得。chrome

其次,JavaScript語言自己是完善的函數式語言,在前端開發時,開發人員每每寫得比較隨意,讓人感受JavaScript就是個「玩具語言」。可是,在Node環境下,經過模塊化的JavaScript代碼,加上函數式編程,而且無需考慮瀏覽器兼容性問題,直接使用最新的ECMAScript 6標準,能夠徹底知足工程上的需求。express

 


 

 

安裝Node.js和npm

(見以前的博客)

安裝成功後使用node -v和npm -v查看版本。

在終端輸入node, 進入Node.js的交互環境。能夠輸入任何js語句。

退出.exit,或者按兩次ctrl+c.

 

關於node的版本選擇。

選擇偶數的版本,node核心團隊維護這類版本的時間達數年之久。具體須要看官網/git(👆的鏈接)

奇數版本,屬於實驗性版本,維護時間1年左右。

維護指:security vulnerability, patches(補丁)

 

 


 

先看廖雪峯

再看視頻(2016版本使用express+ MongoDB)

學習Koa(文章)(廖雪峯上也有)

 

大神的node書,免費

視頻(YoutTube):https://www.youtube.com/watch?v=PT_-u2fFTaI&list=PLguYmmjtxbWHY2vCHIkugUpNdzE3QNOvf&index=4&t=0s

 

 


 

新建一個node文件

在命令行:

//使用mac自帶的vim編輯器,也可使用atom等
vi hello.js

//而後輸入js代碼,保存
//在所存文件的文件夾下,輸入
node hello.js
//在terminal上, 顯示consol.log()打印的代碼。

 

hello.js

'use strict';

console.log('Hello, world.');

//另外,若是不寫‘use strict’,能夠在terminal上使用:
//node --use_strict hello.js

 

在node交互環境下:

輸入的js代碼,每行結果自動打印出來。

這相似進入chrome瀏覽器的控制檯,其實至關於啓動了Node解釋器,每輸入一行就執行一行。

而直接使用node <file-name>, 至關於一次性把文件的源代碼給Node解釋器執行了。

 

使用27存大顯示器的好處:

在編寫JavaScript代碼的時候,能夠一邊在文本編輯器裏寫代碼,一邊開一個Node交互式命令窗口,

在寫代碼的過程當中,把部分代碼粘到命令行去驗證,效率會提高。

 

文件做爲模塊的import和export:

支持es6的語法。如template string。`...``

在node環境下,不支持使用import,export。須要使用module是一個自動生成的對象,用於輸出。

//其基本結構;具體結構進入node,而後輸入global.module。
var module = {
  id: 'xxx',
  exports: {}
}

 

module.exportes = variable

var var1 = require('相對路徑')


⚠️require()方法,是node.js的modules功能,在chrome browser 控制檯上會報告❌ReferenceError,不支持。 

具體見以前的博客:https://www.cnblogs.com/chentianwei/p/10197813.html


 

Node的基本模塊(廖雪峯文章摘錄)

由於Node.js是運行在服務區端的JavaScript環境,服務器程序和瀏覽器程序相比,最大的特色是沒有瀏覽器的安全限制了,並且,服務器程序必須能接收網絡請求,讀寫文件,處理二進制內容,因此,Node.js內置的經常使用模塊就是爲了實現基本的服務器功能。這些模塊在瀏覽器環境中是沒法被執行的,由於它們的底層代碼是用C/C++在Node.js運行環境中實現的。

 

global

進入Node.js交互環境,輸入global.console能夠看到Console對象的屬性

 

process

也是一個對象,表明當前的進程, 輸入global.process,能夠看到相關信息。

> process === global.process
true

 相關命令

> process.version;
'v5.2.0'
> process.platform;
'darwin'
> process.arch;
'x64'
> process.cwd(); //返回當前工做目錄
'/Users/michael'
> process.chdir('/private/tmp'); // 切換當前工做目錄
undefined
> process.cwd();
'/private/tmp'
> process.exit() //退出進程

 

JavaScript程序是由事件驅動執行的單線程模型,Node.js也不例外。

Node.js不斷執行響應事件的JavaScript函數,直到沒有任何響應事件的函數能夠執行時,Node.js就退出了。

// test.js

// process.nextTick()將在下一輪事件循環中調用:
process.nextTick(function () {
    console.log('nextTick callback!');
});
console.log('nextTick was set!');

結果輸出是

nextTick was set!
nextTick callback!

process.nextTick()函數不是立刻執行,而是等到下一次事件循環。

 

Node.js進程自己的事件就是由process對象來處理的。

若是響應exit事件,就能夠在程序退出時執行某個回調函數:

// 程序即將退出時的回調函數:
process.on('exit', function (code) {
    console.log('about to exit with code: ' + code);
});

 

判斷JavaScript的執行環境

有些時候,程序自己須要判斷本身究竟是在什麼環境下執行的,經常使用的方式就是根據瀏覽器和Node環境提供的全局變量名稱來判斷:

if (typeof(window) === undefined) {
  //表明時node.js環境
} else {
  //瀏覽器環境
}

 

fs  -- file system模塊

const fs = require('fs');

 

用於讀寫文件系統的文件。它提供了異步方法。

 

異步讀取文件:

var fs = require('fs')

fs.readFile('sample.txt', 'utf-8', (err, data) => {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
    }
})

 

'sample.txt'是當前路徑內的文件的名字,'utf-8'是文件編碼。

傳入的回調函數接收2個參數err, data,這是標準的Node.js回調函數,第一個參數處理❌,第二個參數處理正確的結果。

例子:

$mkdir htt2
$cd htt2
$npm init -y
$touch fs.js
$vi sample.txt //編寫一些語句,而後:wq

 

'use strict';

var fs = require('fs');

fs.readFile('sample.txt', 'utf-8', function (err, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
        console.log(data.length + ' bytes');
    }
});

 

$node fs 

 

顯示:

hello everybody!

17 bytes

 

⚠️,若是不使用'utf-u', terminal上顯示一個Buffer對象。
<Buffer 68 65 6c 6c 6f 20 65 76 65 72 79 62 6f 64 79 21 0a>

Buffer對象能夠和String對象作轉換。

//fs.js
//在回調函數內加上
        var text = data.toString('utf-8')
        console.log(text)

 

相反使用: Buffer.from(text, 'utf-8')

//node環境下
> var text  = "hello everybody!"> Buffer.from(text, 'utf-8')
<Buffer 68 65 6c 6c 6f 20 65 76 65 72 79 62 6f 64 79 21>

 

同步讀取文件

fs.readFileSync()

'use strict';

var fs = require('fs');

var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);

若是同步讀取文件發生錯誤,則須要用try...catch捕獲該錯誤

 

write 文件

fs.writeFile(fileName, data, callback(err))

  • 文件名
  • 數據若是是String,則默認用utf-8編碼寫入文本文件,若是傳入的是Buffer則寫入的是二進制的文件
  • 回調函數只關心是否成功,因此只有err一個參數。

一樣,有一個同步方法: writeFileSync(fileName, data)

 

fs.stat()

使用fs.stat(fileName, callback(err, stat))來返回一個Stat對象,它包含文件或目錄的詳細信息。

也有同步函數fs.statSync()

 

異步函數爲主

由於Node環境執行的是服務器端代碼,絕大部分須要在服務器上反覆執行邏業務輯的代碼,必須使用異步代碼。否則,同步代碼在執行時期,服務器將中止響應,由於JavaScript只有一個執行線程。

 

服務器啓動時若是須要讀取配置文件,或者結束時須要寫入到狀態文件時,可使用同步代碼,由於這些代碼只在啓動和結束時執行一次,不影響服務器正常運行時的異步執行。


 

 

Stream

一個stream是一個抽象接口,用於Node.js內的streaming data。

Stream module提供了基本的API,能夠創建對象執行stream interface.

 

在Node.js, 流是一個對象。

Node.js提供了許多stream objects,例如,一個發向一個HTTP server的請求,process.stdout。

咱們只須要響應流的事件便可:

  • data事件,表示流的數據已經能夠讀取了
  • end事件,表示這個流已經到末尾了
  • 沒有數據能夠讀取,error事件表示出錯了

例子,讀取流:

var fs = require('fs')
//打開一個只讀的流
var rs = fs.createReadStream('sample.txt', 'utf-8')

rs.on('data', function(chunk) {
  console.log(`Data: ${chunk}`)
})

rs.on('end', () => {
  console.log('End.')
})

rs.on('error', (err) => {
  console.log(`"Error: ${err}`)
})

 

Streams是可讀寫的。全部的流都是EventEmitter類的實例。所以可使用它的實例方法了。這些實例方法大可能是用於監聽事件events及相關操做。

好比上例子的on(eventName, listener),當data事件,end事件完成時,同步執行附加的函數。

 

其實全部的能夠emit事件的objects都是EventEmitter類的實例。這些objects使用on()方法,讓一個或多個函數附加到由這個object發射的event上。

當EventEmitter對象發射emit一個事件時,全部的附加到這個事件的函數被同步地調用。

 

使用下面的語法,取stream module:

const stream = require('stream');

 

stream模塊對正在建立新的類型的流實例的開發者來講,是很是有用的。

Developers who are primarily consuming stream objects will rarely need to use the stream module directly.

 那些主要地消耗流對象的開發者則不多須要直接地使用stream module。

 

Types of Streams

4種基本類型:

  • Writable: 數據能夠被寫入。 fs.createWriteStream()
  • Readable: 數據能夠被讀取。fs.createReadStream()
  • Duplex:  數據可讀寫的。 net.Socket
  • Transform:  這種流是Duplex流,它的輸出某種程度上和輸入相關。例如: crypto streams

 

例子,以流的形式寫入文件,只要不斷調用write()方法,最後end()方法結束。

var ws1 = fs.createWriteStream('sample.txt', 'utf-8')
ws1.write('使用Stream寫入文本數據...\n')
ws1.write('end!')
ws1.end();

var ws2 = fs.createWriteStream('output2.txt');
ws2.write(Buffer.from('使用Stream寫入二進制數據...\n'));
ws2.write(Buffer.from('END.'));
ws2.end();

 

 

全部能夠讀取數據的流都繼承自類stream.Readable

全部能夠寫入的流都繼承自類stream.Writable

 

Pipe

就像能夠把兩個水管串成一個更長的水管同樣,兩個流也能夠串起來。一個Readable流和一個Writable流串起來後,全部的數據自動從Readable流進入Writable流,這種操做叫pipe

 

Readable.pipe(目的地,選項)方法,就能夠作這件事情。

讓咱們用pipe()把一個文件流和另外一個文件流串起來,這樣源文件的全部數據就自動寫入到目標文件裏了,因此,這其實是一個複製文件的程序:

var fs = require('fs');

var rs = fs.createReadStream('sample.txt');
var ws = fs.createWriteStream('copied.txt');

rs.pipe(ws);

同時也有事件pipe, unpipe

Readable.pipe的選項end默認是true, 表示end事件觸發後,會自動關閉Writable流。若是不像自動關閉則:

readable.pipe(writable, { end: false });

 


 

 

http模塊摘要

http模塊會處理Tcp鏈接,解析HTTP。

app不直接和HTTP協議打交道,而是使用http模塊提供的request和response對象

var http = require('http')

var server = http.createServer((req, res) => {
  console.log(`${req.method}:${req.url}`)
  res.writeHead(200, { 'Content-Type': 'text/html'})
  res.end('<h1>hello</h1>')
})

server.listen(3000)

 

request對象應該使用了IncomingMessage類的實例方法method, url

response對象,是類http.ServerResponse的實例,上面的代碼使用了writeHead方法


 

crypto模塊

crypto模塊的目的是爲了提供通用的加密和哈希算法。

包括:a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions.

用純JavaScript代碼實現這些功能不是不可能,但速度會很是慢。

Nodejs用C/C++實現這些算法後,經過cypto這個模塊暴露爲JavaScript接口,這樣用起來方便,運行速度也快。

 

MD5 and SHA1

MD5是一種hash算法,用於給任意數據一個簽名。這個簽名用一個16進制的string表示。

crypto模塊封裝了hash類。

有2種使用Hash類的方法:

  • 做爲一個stream, 能夠讀寫,寫入數據來產生一個可計算的hash digest。
  • 使用hash.update(), hash.digest()方法產生一個可計算的hash。

例子1:

//在terminal進入node環境
const crypto = require('crypto')
const hash = crypto.createHash('sha256')  //產生一個Hash實例
hash.update('some date to hash') //返回
Hash {
  _options: undefined,
  writable: true,
  readable: true,
  [Symbol(kHandle)]: {},
  [Symbol(kState)]: { [Symbol(kFinalized)]: false } } 

hash.digest('hex')  //hex是16進制的意思。
// Prints:
//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50

 

還可使用更安全的sha256sha512

 

例子2

hash對象是一個stream。可讀寫的,當hash被寫入數據後,由於data是能夠被讀的,readable事件會emit.

const crypto = require('crypto');
const fs = require('fs');
const hash = crypto.createHash('sha256');

hash.on('readable', () => {
  // Only one element is going to be produced by the
  // hash stream.
  const data = hash.read();
  if (data) {
    console.log(data.toString('hex'));
    // Prints:
    // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
  }
});

hash.write('some data to hash');
hash.end();

 

 

 

其餘算法見這篇教程

相關文章
相關標籤/搜索