Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境。
Node.js 使用了一個(gè)事件驅(qū)動(dòng)捌锭、非阻塞式 I/O 的模型肯腕,使其輕量又高效。
https://nodejs.org
快速開始 Hello World
Node 是什么
- 簡(jiǎn)史
- 是什么
- Node.js是一個(gè)Javascript運(yùn)行環(huán)境(runtime environment)堡僻,發(fā)布于2009年5月糠惫,由Ryan Dahl開發(fā),實(shí)質(zhì)是對(duì)Chrome V8引擎進(jìn)行了封裝钉疫。Node.js 不是一個(gè) JavaScript 框架硼讽,不同于CakePHP、Django牲阁、Rails固阁。Node.js 更不是瀏覽器端的庫(kù),不能與 jQuery城菊、ExtJS 相提并論备燃。Node.js 是一個(gè)讓 JavaScript 運(yùn)行在服務(wù)端的開發(fā)平臺(tái),它讓 JavaScript 成為與PHP凌唬、Python并齐、Perl、Ruby 等服務(wù)端語言平起平坐的腳本語言客税。
- 發(fā)展史
- 2009年2月况褪,Ryan Dahl在博客上宣布準(zhǔn)備基于V8創(chuàng)建一個(gè)輕量級(jí)的Web服務(wù)器并提供一套庫(kù)。
- 2009年5月霎挟,Ryan Dahl在GitHub上發(fā)布了最初版本的部分Node.js包窝剖,隨后幾個(gè)月里,有人開始使用Node.js開發(fā)應(yīng)用酥夭。
- 2009年11月和2010年4月赐纱,兩屆JSConf大會(huì)都安排了Node.js的講座脊奋。
- 2010年年底,Node.js獲得云計(jì)算服務(wù)商Joyent資助疙描,創(chuàng)始人Ryan Dahl加入Joyent全職負(fù)責(zé)Node.js的發(fā)展诚隙。
- 2011年7月,Node.js在微軟的支持下發(fā)布Windows版本起胰。
- 是什么
- 特征
- 非阻塞I/O(單線程久又、非阻塞)&事件輪詢【Single Threaded Event Loop】
- Node通過事件驅(qū)動(dòng)的方式處理請(qǐng)求時(shí)無需為每一個(gè)請(qǐng)求創(chuàng)建額外的線程。在事件驅(qū)動(dòng)的模型當(dāng)中效五,每一個(gè)IO工作被添加到事件隊(duì)列中地消,線程循環(huán)地處理隊(duì)列上的工作任務(wù),當(dāng)執(zhí)行過程中遇到來堵塞(讀取文件畏妖、查詢數(shù)據(jù)庫(kù))時(shí)脉执,線程不會(huì)停下來等待結(jié)果,而是留下一個(gè)處理結(jié)果的回調(diào)函數(shù)戒劫,轉(zhuǎn)而繼續(xù)執(zhí)行隊(duì)列中的下一個(gè)任務(wù)半夷。這個(gè)傳遞到隊(duì)列中的回調(diào)函數(shù)在堵塞任務(wù)運(yùn)行結(jié)束后才被線程調(diào)用。
- 優(yōu)點(diǎn)
- 高并發(fā)(最重要的優(yōu)點(diǎn))
- 適合I/O密集型應(yīng)用
- RESTful API
- npm迅细,前后端分離
- 缺陷
- 回調(diào)模式下的異步是有明顯缺陷的巫橄,程序的執(zhí)行順序必須依靠回調(diào)來保證,沒有層層回調(diào)茵典,就沒有可以保障的邏輯順序湘换,這也就注定了,node不能做復(fù)雜的業(yè)務(wù)邏輯敬尺。
- 回調(diào)山真不是必須的枚尼。
- 不適合CPU密集型應(yīng)用
- 只支持單核CPU,不能充分利用CPU
- 可靠性低砂吞,一旦代碼某個(gè)環(huán)節(jié)崩潰,整個(gè)系統(tǒng)都崩潰崎溃,原因:?jiǎn)芜M(jìn)程蜻直,單線程。
- Debug不方便袁串,錯(cuò)誤沒有stack trace
- 非阻塞I/O(單線程久又、非阻塞)&事件輪詢【Single Threaded Event Loop】
- nodejs中的庫(kù)方法是異步的概而,異步方法是約定。
環(huán)境配置
Hello World 示例
Once you have installed Node, let's try building our first web server. Create a file named "app.js", and paste the following code:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
After that, run your web server using node app.js, visit http://localhost:3000, and you will see a message 'Hello World'
NPM 使用介紹
- npm 簡(jiǎn)介
- NPM是隨同NodeJS一起安裝的包管理工具囱修,能解決NodeJS代碼部署上的很多問題赎瑰,常見的使用場(chǎng)景有以下幾種:
允許用戶從NPM服務(wù)器下載別人編寫的第三方包到本地使用。
允許用戶從NPM服務(wù)器下載并安裝別人編寫的命令行程序到本地使用破镰。
允許用戶將自己編寫的包或命令行程序上傳到NPM服務(wù)器供別人使用餐曼。
由于新版的nodejs已經(jīng)集成了npm压储,所以之前npm也一并安裝好了。同樣可以通過輸入 "npm -v" 來測(cè)試是否成功安裝源譬。命令如下集惋,出現(xiàn)版本提示表示安裝成功:
$ npm -v
6.4.1
如果你安裝的是舊版本的 npm,可以很容易得通過 npm 命令來升級(jí)踩娘,命令如下:
$ sudo npm install npm -g
Node 架構(gòu)與運(yùn)行原理
Node 架構(gòu)分析
- 架構(gòu)圖
- nodejs組成部分
- v8 engine
- 虛擬機(jī)的功能刮刑,執(zhí)行js代碼
- 提供C++函數(shù)接口,為nodejs提供v8初始化养渴,創(chuàng)建context雷绢,scope等
- libuv
- 基于事件驅(qū)動(dòng)的異步IO模型庫(kù),我們的js代碼發(fā)出請(qǐng)求理卑,最終由libuv完成习寸,而我們所設(shè)置的回調(diào)函數(shù)則是在libuv觸發(fā)
- builtin modules
- 由C++代碼寫成各類模塊,包含了crypto傻工,zlib, file stream etc 基礎(chǔ)功能霞溪。(v8提供了函數(shù)接口,libuv提供異步IO模型庫(kù)中捆,以及一些nodejs函數(shù)鸯匹,為builtin modules提供服務(wù))
- native modules
- 由js寫成,提供我們應(yīng)用程序調(diào)用的庫(kù)泄伪,同時(shí)這些模塊又依賴builtin modules來獲取相應(yīng)的服務(wù)支持
- 建立http server為例
- http server 建立過程
- v8 engine
ES6 features
Node.js ES2015 Support
Node 模塊系統(tǒng)
簡(jiǎn)介
創(chuàng)建模塊
加載模塊
Node 全局對(duì)象
是什么
- JavaScript 中有一個(gè)特殊的對(duì)象殴蓬,稱為全局對(duì)象(Global Object),它及其所有屬性都可以在程序的任何地方訪問蟋滴,即全局變量染厅。
- 在瀏覽器 JavaScript 中,通常 window 是全局對(duì)象津函, 而 Node.js 中的全局對(duì)象是 global肖粮,所有全局變量(除了 global 本身以外)都是 global 對(duì)象的屬性。
- 在 Node.js 我們可以直接訪問到 global 的屬性尔苦,而不需要在應(yīng)用中包含它涩馆。
文件操作
簡(jiǎn)介
- Node.js 提供一組類似 UNIX(POSIX)標(biāo)準(zhǔn)的文件操作API。 Node 導(dǎo)入文件系統(tǒng)模塊(fs)語法如下所示:
- var fs = require("fs")
異步和同步
- Node.js 文件系統(tǒng)(fs 模塊)模塊中的方法均有異步和同步版本允坚,例如讀取文件內(nèi)容的函數(shù)有異步的 fs.readFile() 和同步的 fs.readFileSync()魂那。
- 異步的方法函數(shù)最后一個(gè)參數(shù)為回調(diào)函數(shù),回調(diào)函數(shù)的第一個(gè)參數(shù)包含了錯(cuò)誤信息(error)稠项。
- 建議大家使用異步方法涯雅,比起同步,異步方法性能更高展运,速度更快活逆,而且沒有阻塞精刷。
- 阻塞代碼實(shí)例
- 創(chuàng)建一個(gè)文件 input.txt ,內(nèi)容如下:
Node.js 極簡(jiǎn)教程
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序執(zhí)行結(jié)束!");
以上代碼執(zhí)行結(jié)果如下:
$ node main.js
Node.js 極簡(jiǎn)教程
程序執(zhí)行結(jié)束!
- 非阻塞代碼實(shí)例
- 創(chuàng)建一個(gè)文件 input.txt 划乖,內(nèi)容如下:
Node.js 極簡(jiǎn)教程
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
});
console.log("程序執(zhí)行結(jié)束!");
以上代碼執(zhí)行結(jié)果如下:
$ node main.js
程序執(zhí)行結(jié)束!
Node.js 極簡(jiǎn)教程
以上兩個(gè)實(shí)例我們了解了阻塞與非阻塞調(diào)用的不同贬养。第一個(gè)實(shí)例在文件讀取完后才執(zhí)行完程序。 第二個(gè)實(shí)例我們不需要等待文件讀取完琴庵,這樣就可以在讀取文件時(shí)同時(shí)執(zhí)行接下來的代碼误算,大大提高了程序的性能。
因此迷殿,阻塞是按順序執(zhí)行的儿礼,而非阻塞是不需要按順序的,所以如果需要處理回調(diào)函數(shù)的參數(shù)庆寺,我們就需要寫在回調(diào)函數(shù)內(nèi)蚊夫。
Web 模塊
Web 服務(wù)器簡(jiǎn)介
- Web服務(wù)器一般指網(wǎng)站服務(wù)器,是指駐留于因特網(wǎng)上某種類型計(jì)算機(jī)的程序懦尝,Web服務(wù)器的基本功能就是提供Web信息瀏覽服務(wù)知纷。它只需支持HTTP協(xié)議、HTML文檔格式及URL陵霉,與客戶端的網(wǎng)絡(luò)瀏覽器配合琅轧。
大多數(shù) web 服務(wù)器都支持服務(wù)端的腳本語言(php、python踊挠、ruby)等乍桂,并通過腳本語言從數(shù)據(jù)庫(kù)獲取數(shù)據(jù),將結(jié)果返回給客戶端瀏覽器效床。
目前最主流的三個(gè)Web服務(wù)器是Apache睹酌、Nginx、IIS剩檀。
使用 Node 創(chuàng)建 Web 服務(wù)器
- Node.js 提供了 http 模塊憋沿,http 模塊主要用于搭建 HTTP 服務(wù)端和客戶端,使用 HTTP 服務(wù)器或客戶端功能必須調(diào)用 http 模塊谨朝,代碼如下:
var http = require('http');
以下是演示一個(gè)最基本的 HTTP 服務(wù)器架構(gòu)(使用 8080 端口)卤妒,創(chuàng)建 index.js 文件,代碼如下所示:
實(shí)例
var http = require('http');
var fs = require('fs');
var url = require('url');
// 創(chuàng)建服務(wù)器
http.createServer( function (request, response) {
// 解析請(qǐng)求字币,包括文件名
var pathname = url.parse(request.url).pathname;
// 輸出請(qǐng)求的文件名
console.log("Request for " + pathname + " received.");
// 從文件系統(tǒng)中讀取請(qǐng)求的文件內(nèi)容
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP 狀態(tài)碼: 404 : NOT FOUND
// Content Type: text/plain
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
// HTTP 狀態(tài)碼: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/html'});
// 響應(yīng)文件內(nèi)容
response.write(data.toString());
}
// 發(fā)送響應(yīng)數(shù)據(jù)
response.end();
});
}).listen(8080);
// 控制臺(tái)會(huì)輸出以下信息
console.log('Server running at http://127.0.0.1:8080/');
接下來我們?cè)谠撃夸浵聞?chuàng)建一個(gè) index.html 文件,代碼如下:
index.html 文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Node.js 極簡(jiǎn)教程</title>
</head>
<body>
<h1>我的第一個(gè)標(biāo)題</h1>
<p>我的第一個(gè)段落共缕。</p>
</body>
</html>
執(zhí)行 index.js 文件:
$ node index.js
Server running at http://127.0.0.1:8080/
Request for / received.
{ [Error: ENOENT: no such file or directory, open ''] errno: -2, code: 'ENOENT', syscall: 'open', path: '' }
Request for /index.html received.
Request for /favicon.ico received.
{ [Error: ENOENT: no such file or directory, open 'favicon.ico']
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'favicon.ico' }
Request for /index.html received.
Request for /favicon.ico received.
{ [Error: ENOENT: no such file or directory, open 'favicon.ico']
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'favicon.ico' }
直接訪問 http://127.0.0.1:8080/洗出, 提示 HTTP ERROR 404 Not found:
因?yàn)椋覀兇a里沒有對(duì)根路徑進(jìn)行映射處理图谷。
接著我們?cè)跒g覽器中打開地址:http://127.0.0.1:8080/index.html翩活,顯示如下圖所示:
MySQL數(shù)據(jù)庫(kù)操作
安裝驅(qū)動(dòng)
$ cnpm install mysql
連接數(shù)據(jù)庫(kù)
- 在以下實(shí)例中根據(jù)你的實(shí)際配置修改數(shù)據(jù)庫(kù)用戶名阱洪、及密碼及數(shù)據(jù)庫(kù)名:
test.js 文件代碼:
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);
});
執(zhí)行以下命令輸出結(jié)果為:
$ node test.js
The solution is: 2
數(shù)據(jù)庫(kù) CRUD 操作
- 查詢數(shù)據(jù)
- 查詢數(shù)據(jù)
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();
- 插入數(shù)據(jù)
- 插入數(shù)據(jù)
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();
執(zhí)行以下命令輸出就結(jié)果為:
$ node test.js
--------------------------INSERT----------------------------
INSERT ID: OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 6,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0 }
-----------------------------------------------------------------
- 更新數(shù)據(jù)
- 我們也可以對(duì)數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行修改:
更新數(shù)據(jù)
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 = ['菜鳥移動(dòng)站', '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();
執(zhí)行以下命令輸出就結(jié)果為:
--------------------------UPDATE----------------------------
UPDATE affectedRows 1
-----------------------------------------------------------------
- 刪除數(shù)據(jù)
- 我們可以使用以下代碼來刪除 id 為 6 的數(shù)據(jù):
刪除數(shù)據(jù)
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();
執(zhí)行以下命令輸出就結(jié)果為:
--------------------------DELETE----------------------------
DELETE affectedRows 1
-----------------------------------------------------------------
Kotlin 開發(fā)者社區(qū)
國(guó)內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號(hào),主要分享菠镇、交流 Kotlin 編程語言冗荸、Spring Boot、Android利耍、React.js/Node.js蚌本、函數(shù)式編程、編程思想等相關(guān)主題隘梨。