Node.js是什么
Node.js? is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境。
Node.js 使用了一個(gè)事件驅(qū)動(dòng)、非阻塞式 I/O 的模型,使其輕量又高效。
Node.js 的包管理器 npm,是全球最大的開源庫生態(tài)系統(tǒng)。
以上是中英文兩種方式對Node.js的概括,需要我們明確的是,Node.js既不是一門編程語言,也不是一個(gè)某個(gè)領(lǐng)域的框架,而是一個(gè)javascript的運(yùn)行環(huán)境。
chrome V8引擎
Chrome V8, or simply V8, is an open-source JavaScript engine developed by The Chromium Project for Google Chrome and Chromium web browsers.[5] The project’s creator is Lars Bak.[6] The first version of the V8 engine was released at the same time as the first version of Chrome: September 2, 2008. It has also been used in Couchbase, MongoDB and Node.js that are used server-side.
摘自于wiki,簡而言之,即v8是google開源的javascript引擎,被用來在chrome中解釋javascript。
下載Node.js
從官網(wǎng)可知,當(dāng)前最新版本是9.4.0,長期服務(wù)版本是8.9.4,因?yàn)镹ode.js版本迭代比較快,在開發(fā)中,有時(shí)需要高版本,有時(shí)需要低版本,所以我們不推薦直接下載安裝。我們可以使用Node.js版本管理工具nvm。
NVM
按照文檔進(jìn)行下載,完成之后我們命令行輸入以下命令驗(yàn)證:
nvm --version
有反饋說明安裝成功。
我們通過nvm來查看有哪些node版本可供下載:
nvm ls-remote
v0.1.14
v0.1.15
v0.1.16
v0.1.17
v0.1.18
v0.1.19
v0.1.20
v0.1.21
v0.1.22
v0.1.23
v0.1.24
v0.1.25
v0.1.26
v0.1.27
v0.1.28
v0.1.29
v0.1.30
v0.1.31
v0.1.32
v0.1.33
v0.1.90
v0.1.91
v0.1.92
v0.1.93
v0.1.94
v0.1.95
v0.1.96
v0.1.97
v0.1.98
v0.1.99
v0.1.100
v0.1.101
v0.1.102
v0.1.103
v0.1.104
v0.2.0
v0.2.1
v0.2.2
v0.2.3
v0.2.4
v0.2.5
v0.2.6
v0.3.0
v0.3.1
v0.3.2
v0.3.3
v0.3.4
v0.3.5
v0.3.6
v0.3.7
v0.3.8
v0.4.0
v0.4.1
v0.4.2
v0.4.3
v0.4.4
v0.4.5
v0.4.6
v0.4.7
v0.4.8
v0.4.9
v0.4.10
v0.4.11
v0.4.12
v0.5.0
v0.5.1
v0.5.2
v0.5.3
v0.5.4
v0.5.5
v0.5.6
v0.5.7
v0.5.8
v0.5.9
v0.5.10
v0.6.0
v0.6.1
v0.6.2
v0.6.3
v0.6.4
v0.6.5
v0.6.6
v0.6.7
v0.6.8
v0.6.9
v0.6.10
v0.6.11
v0.6.12
v0.6.13
v0.6.14
v0.6.15
v0.6.16
v0.6.17
v0.6.18
v0.6.19
v0.6.20
v0.6.21
v0.7.0
v0.7.1
v0.7.2
v0.7.3
v0.7.4
v0.7.5
v0.7.6
v0.7.7
v0.7.8
v0.7.9
v0.7.10
v0.7.11
v0.7.12
v0.8.0
v0.8.1
v0.8.2
v0.8.3
v0.8.4
v0.8.5
v0.8.6
v0.8.7
v0.8.8
v0.8.9
v0.8.10
v0.8.11
v0.8.12
v0.8.13
v0.8.14
v0.8.15
v0.8.16
v0.8.17
v0.8.18
v0.8.19
v0.8.20
v0.8.21
v0.8.22
v0.8.23
v0.8.24
v0.8.25
v0.8.26
v0.8.27
v0.8.28
v0.9.0
v0.9.1
v0.9.2
v0.9.3
v0.9.4
v0.9.5
v0.9.6
v0.9.7
v0.9.8
v0.9.9
v0.9.10
v0.9.11
v0.9.12
v0.10.0
v0.10.1
v0.10.2
v0.10.3
v0.10.4
v0.10.5
v0.10.6
v0.10.7
v0.10.8
v0.10.9
v0.10.10
v0.10.11
v0.10.12
v0.10.13
v0.10.14
v0.10.15
v0.10.16
v0.10.17
v0.10.18
v0.10.19
v0.10.20
v0.10.21
v0.10.22
v0.10.23
v0.10.24
v0.10.25
v0.10.26
v0.10.27
v0.10.28
v0.10.29
v0.10.30
v0.10.31
v0.10.32
v0.10.33
v0.10.34
v0.10.35
v0.10.36
v0.10.37
v0.10.38
v0.10.39
v0.10.40
v0.10.41
v0.10.42
v0.10.43
v0.10.44
v0.10.45
v0.10.46
v0.10.47
v0.10.48
v0.11.0
v0.11.1
v0.11.2
v0.11.3
v0.11.4
v0.11.5
v0.11.6
v0.11.7
v0.11.8
v0.11.9
v0.11.10
v0.11.11
v0.11.12
v0.11.13
v0.11.14
v0.11.15
v0.11.16
v0.12.0
v0.12.1
v0.12.2
v0.12.3
v0.12.4
v0.12.5
v0.12.6
v0.12.7
v0.12.8
v0.12.9
v0.12.10
v0.12.11
v0.12.12
v0.12.13
v0.12.14
v0.12.15
v0.12.16
v0.12.17
v0.12.18
iojs-v1.0.0
iojs-v1.0.1
iojs-v1.0.2
iojs-v1.0.3
iojs-v1.0.4
iojs-v1.1.0
iojs-v1.2.0
iojs-v1.3.0
iojs-v1.4.1
iojs-v1.4.2
iojs-v1.4.3
iojs-v1.5.0
iojs-v1.5.1
iojs-v1.6.0
iojs-v1.6.1
iojs-v1.6.2
iojs-v1.6.3
iojs-v1.6.4
iojs-v1.7.1
iojs-v1.8.1
iojs-v1.8.2
iojs-v1.8.3
iojs-v1.8.4
iojs-v2.0.0
iojs-v2.0.1
iojs-v2.0.2
iojs-v2.1.0
iojs-v2.2.0
iojs-v2.2.1
iojs-v2.3.0
iojs-v2.3.1
iojs-v2.3.2
iojs-v2.3.3
iojs-v2.3.4
iojs-v2.4.0
iojs-v2.5.0
iojs-v3.0.0
iojs-v3.1.0
iojs-v3.2.0
iojs-v3.3.0
iojs-v3.3.1
v4.0.0
v4.1.0
v4.1.1
v4.1.2
v4.2.0 (LTS: Argon)
v4.2.1 (LTS: Argon)
v4.2.2 (LTS: Argon)
v4.2.3 (LTS: Argon)
v4.2.4 (LTS: Argon)
v4.2.5 (LTS: Argon)
v4.2.6 (LTS: Argon)
v4.3.0 (LTS: Argon)
v4.3.1 (LTS: Argon)
v4.3.2 (LTS: Argon)
v4.4.0 (LTS: Argon)
v4.4.1 (LTS: Argon)
v4.4.2 (LTS: Argon)
v4.4.3 (LTS: Argon)
v4.4.4 (LTS: Argon)
v4.4.5 (LTS: Argon)
v4.4.6 (LTS: Argon)
v4.4.7 (LTS: Argon)
v4.5.0 (LTS: Argon)
v4.6.0 (LTS: Argon)
v4.6.1 (LTS: Argon)
v4.6.2 (LTS: Argon)
v4.7.0 (LTS: Argon)
v4.7.1 (LTS: Argon)
v4.7.2 (LTS: Argon)
v4.7.3 (LTS: Argon)
v4.8.0 (LTS: Argon)
v4.8.1 (LTS: Argon)
v4.8.2 (LTS: Argon)
v4.8.3 (LTS: Argon)
v4.8.4 (LTS: Argon)
v4.8.5 (LTS: Argon)
v4.8.6 (LTS: Argon)
v4.8.7 (Latest LTS: Argon)
v5.0.0
v5.1.0
v5.1.1
v5.2.0
v5.3.0
v5.4.0
v5.4.1
v5.5.0
v5.6.0
v5.7.0
v5.7.1
v5.8.0
v5.9.0
v5.9.1
v5.10.0
v5.10.1
v5.11.0
v5.11.1
v5.12.0
v6.0.0
v6.1.0
v6.2.0
v6.2.1
v6.2.2
v6.3.0
v6.3.1
v6.4.0
v6.5.0
v6.6.0
v6.7.0
v6.8.0
v6.8.1
v6.9.0 (LTS: Boron)
v6.9.1 (LTS: Boron)
v6.9.2 (LTS: Boron)
v6.9.3 (LTS: Boron)
v6.9.4 (LTS: Boron)
v6.9.5 (LTS: Boron)
v6.10.0 (LTS: Boron)
v6.10.1 (LTS: Boron)
v6.10.2 (LTS: Boron)
v6.10.3 (LTS: Boron)
v6.11.0 (LTS: Boron)
v6.11.1 (LTS: Boron)
v6.11.2 (LTS: Boron)
v6.11.3 (LTS: Boron)
v6.11.4 (LTS: Boron)
v6.11.5 (LTS: Boron)
v6.12.0 (LTS: Boron)
v6.12.1 (LTS: Boron)
v6.12.2 (LTS: Boron)
v6.12.3 (Latest LTS: Boron)
v7.0.0
v7.1.0
v7.2.0
v7.2.1
v7.3.0
v7.4.0
v7.5.0
v7.6.0
v7.7.0
v7.7.1
v7.7.2
v7.7.3
v7.7.4
v7.8.0
v7.9.0
v7.10.0
v7.10.1
v8.0.0
v8.1.0
v8.1.1
v8.1.2
v8.1.3
v8.1.4
v8.2.0
v8.2.1
v8.3.0
v8.4.0
v8.5.0
v8.6.0
v8.7.0
v8.8.0
v8.8.1
v8.9.0 (LTS: Carbon)
v8.9.1 (LTS: Carbon)
v8.9.2 (LTS: Carbon)
v8.9.3 (LTS: Carbon)
v8.9.4 (Latest LTS: Carbon)
v9.0.0
v9.1.0
v9.2.0
v9.2.1
v9.3.0
-> v9.4.0
通過這條命令,驗(yàn)證我們之前的想法,node的版本非常零碎。我們觀察可以看到,有一些版本的名稱叫iojs。這是因?yàn)閚ode團(tuán)隊(duì)曾經(jīng)有一段時(shí)間分成了兩個(gè)團(tuán)隊(duì)。
我們下載v8.9.4并使用
nvm install 8.9.4
nvm use 8.9.4
node --version
v8.9.4
通過以上命令,我們成功下載并安裝了8.9.4版本。
入門
交互式環(huán)境
我們進(jìn)入命令行,輸入以下命令:
node
// 此時(shí)進(jìn)入了交互式環(huán)境
1+1
2
var s = 'hello world'
console.log(s)
hello world
可以看到,我們輸入node命令之后,就好像進(jìn)入了瀏覽器的console控制臺一樣。
node運(yùn)行js文件
創(chuàng)建js文件并編寫代碼:
mkdir node-demo
cd node-demo
touch index.js
vi index.js //寫入console.log('hello world')
node index.js
hello world
我們在index.js中編寫了一條最簡單的語句。然后使用node命令來運(yùn)行這個(gè)文件,命令行正常進(jìn)行了打印。
網(wǎng)絡(luò)應(yīng)用程序
As an asynchronous event driven JavaScript runtime, Node is designed to build scalable network applications. In the following "hello world" example, many connections can be handled concurrently. Upon each connection the callback is fired, but if there is no work to be done, Node will sleep.
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}/`);
});
在官網(wǎng)的About Node.js部分中,有以上一段文字和程序。它告訴我們,Node.js是一個(gè)基于事件驅(qū)動(dòng)的異步j(luò)avascript運(yùn)行環(huán)境,它被設(shè)計(jì)用來構(gòu)建可伸縮的網(wǎng)絡(luò)應(yīng)用程序。
我們訪問localhost:3000,可以正常顯示hello world。
Node.js重要概念
通過上面的學(xué)習(xí),我們已經(jīng)積累了兩個(gè)概念:
- 異步
- 事件驅(qū)動(dòng)
事實(shí)上,如果我們隊(duì)Node.js還有了解的話,我們之后Node.js還有一個(gè)特性:
- 單線程
以上三個(gè)概念或者說特性,是我們了解Node.js的基本路線,也是我們在生產(chǎn)環(huán)境中使用Node.js的理論來源。
異步
異步的另一個(gè)表達(dá)方式叫非阻塞。最直觀的理解就是,我們在讀取一個(gè)超大文件時(shí),cpu不會(huì)死等硬盤去讀取數(shù)據(jù),而是繼續(xù)執(zhí)行后面的代碼,等文件讀取結(jié)束之后,以回調(diào)的形式告知程序。
我們以fs為例,fs是Node.js操作文件的函數(shù)庫:
fs.readFile('/hello.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
我們可以看到,讀取文件是一個(gè)異步的操作,文件的內(nèi)容由回調(diào)返回。這樣的特性,在許多編程語言中是沒有的。
我們通過實(shí)際代碼來測試:
async.js
var fs = require('fs');
fs.readFile('./1.txt',function(err,data){
console.log(data.toString());
});
console.log('hello async.js');
1.txt
hello 1.txt
我們輸入命令:
node async.js
hello async.js
hello 1.txt
我們可以看到,結(jié)果不言而喻。
單線程
我們知道,java語言開發(fā)web應(yīng)用時(shí),就是采用的多線程的模型,每當(dāng)一個(gè)用戶訪問進(jìn)來時(shí),都會(huì)創(chuàng)建一個(gè)線程來處理。這樣的一大弊端就是,頻繁的創(chuàng)建和銷毀線程,對cpu帶來和很大的負(fù)擔(dān),造成了cpu資源的浪費(fèi)。然而,Node.js就走了一條與java完全不同的策略,在Node.js中使用的是單線程的模型。
我們來驗(yàn)證Node.js是否真的是單線程:
修改之前的app.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
console.log('=====================');
//s沒有定義
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
console.log(s);
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
通過以上代碼實(shí)驗(yàn),我們可以這樣認(rèn)識,第一個(gè)用戶成功訪問后,服務(wù)器出現(xiàn)了異常,第二個(gè)用戶再訪問時(shí),服務(wù)已經(jīng)斷開,無法應(yīng)答。所以說,用Node寫后端對我們的代碼質(zhì)量要求非常高,一個(gè)錯(cuò)誤就能搞垮程序,其它人就無法訪問了。單線程的好處就是,減小了創(chuàng)建和銷毀線程的開銷,在低端機(jī)器上也能發(fā)揮最大的性能。
事件驅(qū)動(dòng)
可以說,Node之所以能在單線程環(huán)境中,實(shí)現(xiàn)異步IO,根本原來就是,Node實(shí)現(xiàn)的事件驅(qū)動(dòng)算法機(jī)制。
我們知道,java能實(shí)現(xiàn)異步編程,是因?yàn)橛卸嗑€程的存在,那么Node靠單線程是怎么實(shí)現(xiàn)異步IO的,是一個(gè)值得探討的問題。
我們思考一個(gè)場景,比如說,現(xiàn)在有一家黃燜雞米飯小店,服務(wù)員只有一個(gè)人,她需要兼顧迎接客人,詢問客人吃什么,從后廚上菜品,擦桌子一系列事情。這樣就導(dǎo)致,她要把所有的事情都做好,就不能在一位客人那里等著客人照著菜單選。她會(huì)告訴客人,選好菜直接叫她,她會(huì)利用客人選菜的時(shí)間,去把剛才另外的客人吃完的桌子擦干凈。這就是事件驅(qū)動(dòng)。什么時(shí)間點(diǎn)應(yīng)該去做哪件事情就是異步事件算法應(yīng)該實(shí)現(xiàn)的策略。
所以,Node就跟這位服務(wù)員一樣,累死累活的干活,效率還是非常高的。
npm (Node Package Manager)
npm是node包管理器,類似于java中maven,gradle。
npm
npm之上有非常豐富的第三方j(luò)avascript函數(shù)庫,減少了我們重復(fù)找輪子的過程。比如:
lodash
axios
npm的使用
在node安裝成功之后,npm即會(huì)隨之安裝,我們驗(yàn)證npm是否安裝成功:
npm --vserion
5.6.0
出現(xiàn)數(shù)字,說明本地已經(jīng)有了npm工具。
我們用npm創(chuàng)建項(xiàng)目:
rm -rf node-demo
mkdir node-demo
npm init
一路回車,npm會(huì)在根目錄下生成一個(gè)名為package.json的文件,它記錄這個(gè)項(xiàng)目的相關(guān)信息。
在講解命令用法之前,先梳理一下npm相關(guān)命令:
- npm init 根據(jù)選擇項(xiàng),為項(xiàng)目創(chuàng)建package.json文件
- npm install 根據(jù)package.json中的dependencies和devdependencies下載依賴包
- npm install package-name 下載指定的包,并添加到dependencies中
- npm install package-name --save 下載指定的包,并添加到dependencies中
- npm install package-name --save-dev 下載指定的包,并添加到devdependencies中
- npm install package-name -g 安裝到全局 一般在安裝cli工具時(shí)使用 -g
cat package.json
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
有版本,描述,協(xié)議等內(nèi)容。
我們安裝lodash
npm install lodash --save
成功之后,我們觀察到文件中有了一些變化,package.json中。多了一行內(nèi)容:
"dependencies": {
"lodash": "^4.17.4"
}
--save命令不僅將包安裝,并將包的名稱加入到dependencies中。
根目錄中多了一個(gè)node_modules文件夾,里面存放著我們下載的lodash。
我們所有通過npm install安裝的包都會(huì)放置在node_modules文件夾中。
此時(shí),我們就可以使用lodash:
var _ = require('lodash')
_.forEach([1, 2], function(value) {
console.log(value);
});
1
2
node中,使用require引入模塊。
cnpm
cnpm是淘寶開源的一個(gè)代替npm工具,使用的淘寶鏡像,速度非??臁?br>
cnpm
安裝:
npm install -g cnpm --registry=https://registry.npm.taobao.org
之后,任何使用npm的地方我們都可以使用cnpm。
yarn
yarn也是一個(gè)npm客戶端,與npm相比,速度更快更安全,推薦用yarn來代替npm。
yarn
Node.js模塊化
我們之前用到require函數(shù),知道了可以引入模塊,與之對應(yīng)的還有向外暴露模塊,向外暴露有兩種方式:
- exports
- module.exports
創(chuàng)建util.js
function pingfang(x) {
return x * x ;
}
exports.pingfang = pingfang
修改index.js
var util = require('./util.js')
console.log(util.pingfang(3))
可以正常得出結(jié)果為9.
創(chuàng)建user.js
function User(name,age) {
this.name = age;
this.age = age;
}
User.prototype.say = function() {
console.log('my name is '+ this.name);
}
module.exports = User
修改index.js
var User = require('./user.js')
var user = new User('xiaoming',12);
user.say();
可以正常輸出。
至此,我們就介紹完了Node.js中最重要的內(nèi)容。