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 是一個基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境电谣。
Node.js 使用了一個事件驅(qū)動乡括、非阻塞式 I/O 的模型,使其輕量又高效慧瘤。
Node.js 的包管理器 npm雀哨,是全球最大的開源庫生態(tài)系統(tǒng)艇拍。
以上是中英文兩種方式對Node.js的概括,需要我們明確的是骏掀,Node.js既不是一門編程語言鸠澈,也不是一個某個領(lǐng)域的框架,而是一個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ā)中鹉勒,有時需要高版本拳缠,有時需要低版本,所以我們不推薦直接下載安裝贸弥。我們可以使用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)有一段時間分成了兩個團(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
// 此時進(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)行這個文件穷劈,命令行正常進(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是一個基于事件驅(qū)動的異步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)積累了兩個概念:
- 異步
- 事件驅(qū)動
事實(shí)上,如果我們隊(duì)Node.js還有了解的話疾渣,我們之后Node.js還有一個特性:
- 單線程
以上三個概念或者說特性,是我們了解Node.js的基本路線崖飘,也是我們在生產(chǎn)環(huán)境中使用Node.js的理論來源榴捡。
異步
異步的另一個表達(dá)方式叫非阻塞
。最直觀的理解就是朱浴,我們在讀取一個超大文件時吊圾,cpu不會死等硬盤去讀取數(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);
});
我們可以看到檀何,讀取文件是一個異步的操作,文件的內(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)用時施敢,就是采用的多線程的模型周荐,每當(dāng)一個用戶訪問進(jìn)來時狭莱,都會創(chuàng)建一個線程來處理。這樣的一大弊端就是概作,頻繁的創(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)識,第一個用戶成功訪問后集绰,服務(wù)器出現(xiàn)了異常规辱,第二個用戶再訪問時,服務(wù)已經(jīng)斷開栽燕,無法應(yīng)答罕袋。所以說,用Node寫后端對我們的代碼質(zhì)量要求非常高碍岔,一個錯誤就能搞垮程序浴讯,其它人就無法訪問了。單線程的好處就是蔼啦,減小了創(chuàng)建和銷毀線程的開銷榆纽,在低端機(jī)器上也能發(fā)揮最大的性能
。
事件驅(qū)動
可以說捏肢,Node之所以能在單線程環(huán)境中奈籽,實(shí)現(xiàn)異步IO,根本原來就是鸵赫,Node實(shí)現(xiàn)的事件驅(qū)動算法機(jī)制
衣屏。
我們知道,java能實(shí)現(xiàn)異步編程辩棒,是因?yàn)橛卸嗑€程的存在狼忱,那么Node靠單線程是怎么實(shí)現(xiàn)異步IO的,是一個值得探討的問題
一睁。
我們思考一個場景藕赞,比如說,現(xiàn)在有一家黃燜雞米飯小店卖局,服務(wù)員只有一個人
斧蜕,她需要兼顧迎接客人,詢問客人吃什么砚偶,從后廚上菜品批销,擦桌子
一系列事情洒闸。這樣就導(dǎo)致,她要把所有的事情都做好均芽,就不能在一位客人那里等著客人照著菜單選丘逸。她會告訴客人,選好菜直接叫她掀宋,她會利用客人選菜的時間深纲,去把剛才另外的客人吃完的桌子擦干凈。這就是事件驅(qū)動
劲妙。什么時間點(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即會隨之安裝,我們驗(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會在根目錄下生成一個名為package.json
的文件陶贼,它記錄這個項(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工具時使用 -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
中肩钠。
根目錄中多了一個node_modules
文件夾泣港,里面存放著我們下載的lodash暂殖。
我們所有通過npm install
安裝的包都會放置在node_modules文件夾中。
此時当纱,我們就可以使用lodash:
var _ = require('lodash')
_.forEach([1, 2], function(value) {
console.log(value);
});
1
2
node中,使用require
引入模塊。
cnpm
cnpm是淘寶開源的一個代替npm工具诺擅,使用的淘寶鏡像咒程,速度非常快箫柳。
cnpm
安裝:
npm install -g cnpm --registry=https://registry.npm.taobao.org
之后手形,任何使用npm的地方我們都可以使用cnpm
。
yarn
yarn也是一個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)容篙梢。