简介与安装
¶什么是 Node.js
-
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
-
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
-
Node.js 的包管理器 npm,是全球最大的开源库生态系统。
Node.js 可以解析JS代码(没有浏览器安全级别的限制)提供很多系统级别的API,如:
-
文件的读写
-
进程的管理
-
网络通信
-
……
¶准备 Node.js
使用 nvm 可以在本地安装并维护多个Node.js的版本
1、项目地址:
https://github.com/creationix/nvm/blob/master/README.md
2、配置加速镜像:
export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node
¶命令行中的体验
$ node 进入命令行
-
在浏览器和node命令行中运行代码
function add(x, y){ console.log(x+y); } add(3, 4)
-
在浏览器和node命令行里调用 window, process 两个对象
nodejs可以调用操作系统内核 api(io、进程等);浏览器中可以调用浏览器内核 api(bom、dom)
¶执行 .js 文件
-
编写 index.js 文件
console.log('hello'); function add(x,y) { console.log(x+y); } add(6,7);
-
node index.js
执行代码(省略.js
后缀也可以)
¶一些工具
-
npm:包管理器
-
cnpm:使用国内镜像
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
-
gulp:文件管理、css预编译等
-
@vue/cli:vue 官方脚手架工具
-
nodemon:可以实时监听脚本的变化以及自动执行
cnpm install -g nodemon nodemon xxx.js
¶使用不同版本的 Node.js
查看有哪些版本:
nvm ls
通过以下两个命令都可以查看正在使用的版本
# 1
nvm run node –version
# 2
npm -v
以某个版本运行某个脚本文件:
-
方式一
# 直接通过 nvm run 命令执行脚本 nvm run v6.11.2 script.js
-
方式二
# 在当前目录创建一个.nvmrc 版本文件, 文件内容为某个版本,如:8.4.0。然后执行以下命令 nvm use # 再执行具体的脚本 node script.js
Node.js 特性
¶[CommonJS规范](http://www.commonjs.org
)
¶Node.js 模块
¶package.json
在当前项目目录(ECMAScript工程)下创建一个 package.json
文件记录工程的信息以及其依赖的模块,由 npm 或者 yarn 等工具读取管理。使用命令即可在当前目录下创建一个该文件,即初始化一个工程:
npm init
{
"name": "nodejs-day1-1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
// commonjs版本约定有三位,分别是 major、minor、patch
// ^ 表示 major 固定,取最新版本;~ 表示 major 和 minor 固定,取最新版本;* 表示取最新版本
"underscore": "^1.8.3"
},
// 开发环境的依赖。
"devDependencies": {
"cheerio": "^0.22.0",
"gulp": "*"
},
// scripts 模块定义一些自定义 npm 命令。如下面生成的命令为 npm test、npm start;分别将它们的 value 作为命令执行。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC"
}
¶安装模块
当使用 -g
的时候表示在全局安装模块
# 在全局安装 request 模块
npm install request -g
没有 -g
的时候表示在当前工程中创建一个模块,默认认为在当前目录下存在一个 package.json
文件:
npm install request --save
--save
表示将这个模块记录到当前项目的 package.json 的依赖项中:
# package.json 的 dependencies 中记录了 request 模块
{
"name": "hello",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"request": "^2.81.0"
}
}
当在当前工程安装完成依赖模块之后,会在工程目录下生成一个 node_modules
目录,里面就是安装的依赖包
¶模块定义、导出和导入
¶commonjs
导出模块为 hello 函数为一个名为 hello 的模块
const hello = () => {
console.log('hello ~');
}
//module.exports 是写死的语法,相当于一个模块集合对象,下面的 require 得到的就是这个对象,通过 .模块名 获取具体的模块
module.exports.hello = hello
导入自己定义的模块,使用 ./
表示这个模块是在当前自己项目中定义的,避免如扫描内置模块或者第三方模块
// require 中指定模块所在的 js 文件路径
const greeting = require('./src/greeting.js')
greeting.hello()
¶模块化参考阅读
ECMAScript 6 modules: the final syntax
¶npm 的一些命令
# -g、--global 表示全局。不加就是当前项目
npm list # 查看安装包列表
npm info # 查看具体包的所有版本及其它详细信息
npm init # 初始化工程包管理文件配置信息
npm install # 按照当前目录的 package.json 文件依赖进行安装
npm install @ # 安装具体版本的包
npm install --save # 安装模块并添加到配置文件依赖项
npm uninstall --save-dev # 卸载模块并将其在配置文件的开发依赖项中删除
npm outdated # 显示安装的包的版本、配置文件中依赖的可以下载的最新版本、最新版本
npm cache clean # 清除 npm 包管理缓存
Node.js 内置常用模块
¶URL
对一个字符串安装 URL 格式解析成一个 json 对象
// 第一个参数传入的就是 URL 字符串
// 第二个参数是一个boolean值,表示是否将 query 串也解析成一个json对象,否则原封不同就是一个字符串('&'分隔)
// 第三个参数也是一个boolean值,表示在协议未确定的情况下是否推测解析出 host 和 port
url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
// 将上面的返回值,即一个 json 对象转成一个 url 字符串
url.format(urlObject)
// 拼接 URL 字符串,from 一般是一个 host、to 一般是一个 path
url.resolve(from, to)
¶querystring
// 将一个对象转成一个字符串,默认按照 http URL 中的 query 串的格式进行转换
// 第一个参数就是要转换的 json 对象
// 第二个参数是每一个属性键值对之间的分隔符
// 第三个参数是每一对属性键值之间的分隔符
querystring.stringify(obj[, sep[, eq[, options]]])
// 和上面的方法相反
querystring.parse(str[, sep[, eq[, options]]])
// 对传入字符串进行 URL 编码
querystring.escape(str)
// 对传入字符串进行 URL 解码
querystring.unescape(str)
¶http、https
小爬虫实现:
var http = require('http')
var https = require('https')
var cheerio = require('cheerio')
var url = 'https://www.lagou.com/'
function filterMenu(html) {
var $ = cheerio.load(html)
var menu = $('.menu_main')
var menuData = []
menu.each(function(index, value){
var menuTitle = $(value).find('h2').text()
var menuLists = $(value).find('a')
var menuList = []
menuLists.each(function(index, value){
menuList.push($(value).text())
})
menuData.push({
menuTitle: menuTitle,
menuList: menuList
})
})
return menuData;
}
function printMenu(menu) {
menu.forEach(function(value){
console.log(value.menuTitle + '\n')
value.menuList.forEach(function(value){
console.log(value)
})
})
}
https.get(url, function(res){
var html = ''
res.on('data', function(data){
html += data
})
res.on('end', function(){
var result = filterMenu(html)
printMenu(result)
})
res.on('error', function(err){
console.log(err)
})
})
¶事件监听处理机制
// 引入事件机制模块
const EventEmitter = require('events')
// 实现自己的类继承事件机制类
class Player extends EventEmitter {}
// 新建事件机制对象
var player = new Player()
//on 方法表示发布某个事件监听及其处理器,且一直监听;once 方法表示只监听处理一次该事件
//第一个参数是事件名称,第二个参数是事件处理函数
player.once('play', (track) => {
console.log(`正在播放:《${track}》`)
})
//emit 方法表示触发某个事件
//第一个参数是事件名称,第二个参数是事件本身
player.emit('play', '精绝古城')
player.emit('play', '黄皮子坟')
¶File System
- 得到文件与目录的信息:stat
- 创建一个目录:mkdir
- 创建文件并写入内容:writeFile,appendFile
- 读取文件的内容:readFile
- 列出目录的东西:readdir
- 重命名目录或文件:rename
- 删除目录与文件:rmdir,unlink
¶Stream
- 读取文件流
- 可读流的事件
- 可写的文件流
- pipe链式使用
- pipe
¶网络
¶net 模块 socket 编程
SocketServer.js:
var net = require('net')
var chatServer = net.createServer(),
clientMap = new Object()
var i = 0 //连接名称的流水号
chatServer.on('connection', function (client) {
console.log('客户端有人连接~')
client.name = ++i
clientMap[client.name] = client
// 对客户端发送消息的监听
client.on('data', function (data) {
console.log('客户端传来:' + data)
broadcast(data, client)
})
// 数据错误事件处理
client.on('error', function (e) {
console.log('client error' + e);
client.end()
})
// 客户端关闭事件
client.on('close', function (data) {
delete clientMap[client.name]
console.log(client.name + '下线了');
broadcast(client.name + '下线了', client)
})
})
// 消息广播
function broadcast(message, client) {
for (var key in clientMap) {
clientMap[key].write(client.name + 'say:' + message + '\n')
}
}
chatServer.listen(9000)
SocketClient.js:
var net = require('net')
var port = 9000
var host = '127.0.0.1'
var client = new net.Socket()
client.setEncoding = 'UTF-8'
// 连接服务器
client.connect(port, host, function () {
client.write('您好')
})
client.on('data', function (data) {
console.log('服务端传来:' + data);
say()
})
client.on('error', function (err) {
console.log('error' + err);
})
client.on('close', function () {
console.log('connection closeed');
})
const readline = require('readline')
const r1 = readline.createInterface({
input: process.stdin,
output: process.stdout
})
function say() {
r1.question('请输入:', (inputStr) => {
if (inputStr != 'bye') {
client.write(inputStr + '\n')
} else {
client.distroy() //关闭连接
r1.close()
}
})
}
¶浏览器原生支持 WebSocket
WsServer.js
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({port: 9000})
var clientMap = new Object()
var i = 0
wss.on('connection', function (ws) {
console.log(ws + '上线')
ws.name = ++i
clientMap[ws.name] = ws
ws.on('message', function (message) {
broadcast(message, ws)
})
ws.on('close', function () {
// global.gc() //调用内存回收
console.log('离开');
})
})
function broadcast(msg, ws) {
for (var key in clientMap) {
clientMap[key].send(ws.name + '说: ' + msg)
}
}
WsClient.js,被聊天框页面用 script 标签引入,可以看到 WebSocket 对象是浏览器内置对象,不用导入:
var ws = new WebSocket('ws://127.0.0.1:9000/')
ws.onopen = function () {
ws.send('大家好')
}
ws.onmessage = function (event) {
var chatroot = document.querySelector('#chatroom')
chatroom.innerHTML += '
' + event.data
}
ws.onclose = function () {
alert('Closed')
}
ws.onerror = function (err) {
alert('Error:' + err)
}
聊天框页面:
ws client
WebSocket
¶兼容性好的 socketio
上面的 WebSocket 实现需要兼容 html5 的浏览器才可行。Socket io 则兼容一切浏览器。
第三方模块
¶Async
示例:
var async = require('async')
console.time('test')
// 串行无关联:series 方法
// 两个参数,第一个参数是一个函数数组,数组里面的函数将会被串行调用。第二个参数是一个回调函数,将会在函数数组里面的函数都调用完成后被调用
async.series([
function (callback) {
setTimeout(function(){
callback(null, 'one')
}, 2000)
},
function (callback) {
setTimeout(function(){
callback(null, 'two')
}, 5000)
}
], function(err, results){
console.log(results)
console.timeEnd('test')
})
async.series({
one: function (callback) {
setTimeout(function(){
callback(null, '1')
}, 1000)
},
two: function (callback) {
setTimeout(function(){
callback(null, '2')
}, 2000)
}
}, function(err, results){
console.log(results)
console.timeEnd('test')
})
// 并行无关联:parallel 方法
// 两个参数,第一个参数是一个函数数组,数组里面的函数将会被异步调用。第二个参数是一个回调函数,将会在函数数组里面的函数都调用完成后被调用
async.parallel([
function (callback) {
setTimeout(function(){
callback(null, 'one')
}, 2000)
},
function (callback) {
setTimeout(function(){
callback(null, 'two')
}, 5000)
}
], function(err, results){
console.log(results)
console.timeEnd('test')
})
// 串行有关联:waterfall 方法
// 两个参数
// 第一个参数是一个函数数组,数组里面的函数将会被串行调用,且前一个函数的参数 callback 就是下一个函数的引用,依次形成过滤器/责任链模式。
// 第二个参数是一个回调函数,将会在函数数组里面的函数都调用完成后被调用
async.waterfall([
function (callback) {
callback(null, 'one', 'two')
},
function (arr1, arr2, callback) {
callback(null, arr1, arr2, 'three')
},
function (arr1, arr2, arr3, callback) {
callback(null, [arr1, arr2, arr3, 'done'])
}
], function(err, results){
console.log(results)
})
¶Express
一个 Web 开发脚手架工具。 使用它可以生成一个格式化的工程项目,里面包含了一些已经写好的结构化代码,以及一个依赖了固定功能的 Web 开发模块的 package.json 文件。基于这个工程就可以快速开发一个 Web 项目。
¶EJS 简介
EJS 是 Express 中依赖的一个模板引擎语言。
EJS是一个简单高效的模板语言,通过数据和模板,可以生成HTML标记文本。可以说EJS是一个JavaScript库,EJS可以同时运行在客户端和服务器端,客户端安装直接引入文件即可,服务器端用npm包安装。
¶EJS 的特点
-
快速编译和渲染
-
简单的模板标签
-
自定义标记分隔符
-
支持文本包含
-
支持浏览器端和服务器端
-
模板静态缓存
-
支持express视图系统
¶EJS 的成员函数
Render(str,data,[option]):直接渲染字符串并生成html
- str:需要解析的字符串模板
- data:数据
- option:配置选项
¶EJS 的常用标签
<% %>
流程控制标签<%= %>
输出标签(原文输出HTML标签)<%- %>
输出标签(HTML会被浏览器解析)<%# %>
注释标签- % 对标记进行转义
¶Mocha
Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。所谓"测试框架",就是运行测试的工具。通过它,可以为JavaScript应用添加测试,从而保证代码的质量。
¶chai
assert/断言库。
- should风格的断言
- expect风格的断言