NodeJS是C語言開發的V8引擎,代碼格式是JS寫法的,做了服務器語言的一門編程語言
NodeJS更新速度非常的快,所以很多的API更改刪除很快,所以要保證版本一致,框架也是,插件也是,不符合版本運行起來就會報錯,說找不到這個方法什么的
我們知道瀏覽器JS分為Dom+Bom+ES56789,而NodeJS明顯沒有Dom,Bom是運行環境帶來的方法,Bom在瀏覽器是window對象,cookie,瀏覽歷史等等,而NodeJS就沒有這些了,他的Bom是下載node的時候帶來的,也就是官網文檔顯示的那些,ES則是跟瀏覽器一樣的,所以需要先會ES作為前提,ES學習可以查看JS分類
下面的筆記來自
NodeJS官方文檔,v12
掘金大佬的總結
具體的常用的知識點有
- global全局
- buffer二進制
- console控制台
- crypto加密
- events事件
- module模塊
- http
- path
- fs文件
- 計時器
- url
- zlib壓縮
- querystring
global全局
這個就是瀏覽器的window,在nodejs里是沒有window變量的
看過nodejs代碼的人應該知道,nodejs跟java一樣,有很多內置的方法是需要引入模塊的,比如你要操作文件,不是直接調用fs的方法,需要先引入內置的fs模塊才行,java也是,就算是生成一個數組也需要引入系統內置的Array-jar包,而全局變量就是指不需要引入模塊的就能使用的,
上面的buffer,console,module,計時器,當前運行路徑,process就不需要引入模塊
module模塊
模塊最怕的就是相互引用
記得ES6的模塊化嗎
// 暴露多個
export var firstName = 'Michael';
export var lastName = 'Jackson';
// 只能暴露一個
export default function () {
console.log('foo');
}
// 引入
import { firstName, lastName, year } from './profile.js';
nodejs模塊
// 暴露多個
exports.age = '123';
exports.name = "abc";
// 暴露一個
// 沒有
// 引入
// 這個a一定是個對象,不能跟es6模塊化一樣實現解構賦值
const a = require('./a.js');
路徑
不要使用相對路徑,因為nodejs運行的時候,相對路徑是相對於工作路徑,比如a.js旁邊就有個img文件夾里面有個圖片,直接執行a.js就可以用相對路徑去拿到這個圖片,但是如果是a.js被別的文件夾引入后執行的,那他的相對路徑就找不到img文件夾了
console.log('__dirname:', __dirname); // 當前所在絕對路徑文件夾
console.log('__filename:', __filename); // 當前所在絕對路徑文件
// 這個是path模塊的方法
// 如果不希望自己手動處理 / 的問題,使用 path.join
path.join(__dirname, 'view.html');
path.join(__dirname, 'views', 'view.html');
process
進程,當前主進程,有個env全局變量了解一下
process.env.NODE_ENV = 'development';
console.log(process.env.NODE_ENV);
// 防止起高樓,樓塌了
// 在原生node中有一個 process.on方法,可以守護你的進程即使報錯也不崩潰:
process.on('uncaughtException',(err)=>{
console.error(err)
})
buffer
用來轉碼的還有什么二進制轉六進制什么的,重要的是可以把base64轉文件
// 引入fs模塊
const fs = require('fs');
const uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...';
const base64Data = uri.split(',')[1];
const buf = Buffer(base64Data, 'base64');
fs.writeFileSync(`${__dirname}/secondmonkey.png`, buf);
計時器和console
這兩個跟瀏覽器一樣的用法
crypto加密
內置有很多的出名的加密方式比如MD5
和SHA256
,但是不能解密,常用在連接微信服務器的時候生成簽名
const crypto = require('crypto');
const hash = crypto.createHash('md5');
// 可任意多次調用update():
hash.update('Hello, world!');
hash.update('Hello, nodejs!');
console.log(hash.digest('hex')); // 7e1977739...
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret).update('I love cupcakes').digest('hex');
console.log(hash.digest('hex')); // c0fa131bd7...
events事件
這是一個訂閱發布的模式,用一個數組存起來效果也一樣,很少用到,封裝插件和框架用的
const EventEmitter = require('events').EventEmitter;
class MusicPlayer extends EventEmitter {
constructor() {
super();
this.playing = false;
}
}
const musicPlayer = new MusicPlayer();
musicPlayer.on('play', function (track) {
this.playing = true;
});
musicPlayer.on('stop', function () {
this.playing = false;
});
musicPlayer.emit('play', 'The Roots - The Fire');
setTimeout(function () {
musicPlayer.emit('stop');
}, 1000);
fs只記住他能轉換文件格式編碼,判斷文件是否存在,文件監聽【vue的熱更新原理】,把文件讀取的功能都放在stream學習
fs
這個模塊的方法很多,常用的只要記住他可以判斷文件是否存在,對文件進行監聽【熱更新原理】,文件轉格式【base64上傳】,文件讀取,文件讀寫有兩個系列的API,一個是read_write,是讀取文件內部的文字代碼什么的【babel編譯】,一個是stream,是文件的整體傳輸
const fs = require('fs');
// 判斷文件是否存在,原來的fs.exists已經廢棄了
fs.stat("./txtDir", function(err, stats) {
console.log(stats.isDirectory());
console.log(stats);
});
// 文件監聽,fs.watchFile 比 fs.watch 低效,但更好用
fs.watch('./watchdir', console.log); // 穩定且快
fs.watchFile('./watchdir', console.log); // 跨平台
// 文件轉格式和read_write
// 生成 data URI
const fs = require('fs');
const mime = 'image/png';
const encoding = 'base64';
const base64Data = fs.readFileSync(`${__dirname}/monkey.png`).toString(encoding);
const uri = `data:${mime};${encoding},${base64Data}`;
console.log(uri);
// data URI 轉文件
const fs = require('fs');
const uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...';
const base64Data = uri.split(',')[1];
const buf = Buffer(base64Data, 'base64');
fs.writeFileSync(`${__dirname}/secondmonkey.png`, buf);
// stream和pipe
// 文件管道
const r = fs.createReadStream('file.txt');
const w = fs.createWriteStream('new.txt');
r.pipe(w);
// http管道
const http = require('http');
http.createServer((req, res) => {
// 讀取文件后傳給瀏覽器
fs.createReadStream(`${__dirname}/index.html`).pipe(res);
}).listen(8000);
// 壓縮,不經過z管道只能算是改名字
const zlib = require('zlib');
const r = fs.createReadStream('file.txt');
const z = zlib.createGzip();
const w = fs.createWriteStream('file.txt.gz');
r.pipe(z).pipe(w);
path
用來解析路徑和拼接路徑的
為什么需要
一,路徑的加減法計算自己很難做,就像上面說的工作路徑__dirname計算一樣
二,不同虛擬機的路徑表示是不一樣的,在linux是雙斜桿,在別的地方可能是冒號,反斜杠,為了能在別的系統上運行,用內置的方法拼接是最穩妥的
const path = require('path');
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
path.parse('C:\\path\\dir\\file.txt');
// 返回:
// { root: 'C:\\',
// dir: 'C:\\path\\dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file' }
http 和 url 和 querystring
http模塊是nodejs最核心的模塊,也是他作為服務器語言的原因
url模塊是處理訪問路徑的
querystring模塊是處理請求體的數據的
const http = require("http");
const url = require("url");
const querystring = require("querystring");
// createServer 核心模塊的核心方法,回調函數有兩個參數
// 第一個參數request,表示請求,所有請求的相關數據都在里面
// 第二個參數是response,表示響應,通過調用它的內部方法向前端發送數據
http.createServer((request, response) => {
// 當前服務器訪問的方式
console.log(request.method);
// 把reques.url轉換為一個URL對象,第二個參數true一定要
let myUrl = url.parse(request.url, true);
// 把reques.url轉換為一個URL對象,並且將query,search等屬性轉換為對象
console.log("url對象:", myUrl);
// 獲取myUrl 的hash部分(在vue和react中有的是用hash) #test
console.log("hash:"+myUrl.hash);
// 獲取myUrl中包括端口的域名部分 http://www.test.com:80
console.log("host:"+myUrl.host);
// 獲取myUrl中的域名部分 http://www.test.com
console.log("hostname:"+myUrl.hostname);
// 獲取路徑部分 /a/b?id=10
console.log("path:"+myUrl.path);
// 獲取myUrl端口 80 8080
console.log("port:"+myUrl.port);
// 獲取請求的參數 ?id=10
console.log("search:"+myUrl.search);
// 獲取接口路徑 /a/b
console.log("pathname:" +myURL.pathname);
// 獲取請求的參數,整理格式,這個就是get請求的參數
console.log("query:"+myUrl.query);
// 通過判斷路徑,做接口
if(myURL.pathname=="/get"){
// 獲取參數myUrl.query,然后去數據庫數據什么的...
let myUrl = url.parse(request.url, true);
console.log(myUrl)
// 設置響應頭部信息及編碼
response.writeHead(200, {"Content-Type": "text/plain;charset=UTF-8"});
// 返回
response.write("成功");
response.end('Responses');
}else if(myURL.pathname=="/post"){
// get請求的參數很好獲得,但是post就不一樣了
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
// 解析參數
body = url.parse(body);
console.log(body)
// 設置響應頭部信息及編碼
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf8'});
// 返回
response.write("成功");
response.end('Responses');
}else{
response.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
response.end('<h1>404 Not Found!</h1>')
}
}).listen(3000);
dgram數據報
就是socket通信,插件封裝好了,就用插件就行
其他
難道我大nodejs就這么點東西?
上面都是最基礎,最實用的模塊和代碼,每一個都能深挖出很多的東西
高端的還有子進程,多線程
框架選擇,數據庫連接,分布式,集群什么鬼的后續慢慢寫
為什么需要使用框架
按照上面的http示例代碼無限的if-else下去是可以做一個原生的服務器的,但是最后會又臭又長,所有就需要分成一個個請求出來寫,並且我們每次返回都需要去設定響應頭格式什么的,判斷非常的復雜,后來就演變出來很多的框架,比如express和koa,下一篇koa
NodeJS 和 Java的區別
查看【Linux/IO】筆記