1.Node.js介绍
1.1 node.js是什么
- (1) Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
- Node.js不是一门语言
- Node.js不是库、不是框架
- Node.js是一个Javascript运行时环境
- 简单来讲就是Node.js可以解析和执行JavaScript代码
- 以前只有浏览器可以解析和执行JavaScript代码,也就是说现在的JavaScript可以完全脱离浏览器来运行,这一切归功于Node.js
- (2)浏览器中的JavaScript
- EcmaScript
- 基本语法
if
,var
,function
,Object
,Array
- BOM
- DOM
- 基本语法
- EcmaScript
- (3)Node.js中的JavaScript
- 没有BOM和DOM
- EcmaScript
- 在Node这个JavaScript执行环境中为JavaScript提供了一些服务器级别的操作 API
- 例如:文件的读写、网络服务的构建、网络通信、http服务器…
- (4) Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.
- event-driven 事件驱动
- non-blocking I/O model 非阻塞IO模型 (异步)
- lightweight and efficient.轻量和高效
- (5)Node.js’ package ecosystem,npm, is the largest ecosystem of open source libraries in the world.
- npm是世界上最大的开源库生态系统
- 绝大多数的JavaScript相关的包都存放在了npm上,这样做的目的是为了让开发人员更方便的去下载使用
- ·
npm install jquery
1.2 Node.js能作什么
预备知识:HTML,CSS,JavaScript,简单的命令行操作
- Web服务器后台
- 命令行工具
- 对于前端开发工程师来讲,接触 node 最多的是它的命令行工具,自己写的很少,主要是使用别人第三方的
- webpack
- gulp
- npm
1.3 能学到什么
- B/S教程 (Browser-Server),任何服务端技术这种BS编程模型都是一样的,和语言无关。
- 模块化教程
- RequireJS
- SeaJS
- Node常用API
- 回调函数
- Promise
- async
- generator
- 异步编程
- Express Web开发框架
- Ecmascript6
- 学习Node不仅会帮助我们打开服务器黑盒子,同时会帮助你学习以后的前端高级内容
- Vue.js
- React
- angular
1.4 一些注意事项
- 确认Node环境是否安装成功
node -v
或node -version
出现版本号npm -v
- 文件名不能用node.js命名。
- 在Node.js中,采用ES6进行编码,没有BOM和DOM,和浏览器中的JavaScript不一样
//这时会报错 console.log(window); console.log(document);
1.5 Node.js中的JavaScript
- EcmaScript (没有BOM和DOM)
- 核心模块
- 用户自定义模块
- 第三方模块
核心模块
node 为 JavaScript 提供了很多服务器级别的 API ,这些 API 绝大多数都被包装到了一个具名的核心模块中了。
例如文件操作的fs
核心模块、http 服务构建的http
模块、path
路径操作模块、os
操作系统信息模块等等。
要想使用核心模块,就必须 const fs = require("fs);
- 文件操作的 fs
- http 服务的 http
- url 路径操作模块
- os 操作系统信息
用户自定义模块
-
require
-
exports
第三方模块 -
art-template,必须通过npm来下载才能使用
2 .Node 中的 JS
2.1 文件的操作
-
fs 是 file-system 的简写,就是文件系统的意思。
在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块。
在fs这个核心模块中就提供了所有文件操作相关的API
1.文件的读取//1.使用 require 方法加载 fs 核心模块 const fs = require('fs'); //2.读取文件 // 第一个参数是要读取的文件路径 // 第二个参数是回调函数 // 如果读取成功 // data: 数据 // error:null // 如果读取失败 // data: undefined // error: 错误对象 fs.readFile('./data/hello.txt',function (error,data) { //文件中存储的其实都是二进制数据 0 1 //但是这里打印出来的却不是 0 和 1 原因是二进制转换成了 16 进制 //我们可以用tostring()来转换 //console.log(data); //console.log(data.toString()); //错误判断:通过判断 error 来确定是否有错误发生 if (error) { console.log('读取文件失败'); return; } console.log(data.tostring()); });
2.文件的写入
const fs = require('fs'); //第一个参数:文件路径 //第二个参数:文件内容 //第三个参数:回调函数 // 成功:文件写入成功;error 是 null // 失败:文件写入失败,error 是错误对象 fs.writeFile('./data/hello.txt','你好,我是Node.js',function (error) { if (error){ console.log('文件写入失败') }else{ console.log('文件写入成功') } })
-
fs 提供了异步和同步两种方法
异步//异步读取文件 fs.readFile('../a.txt' , function(err , data){ if(err){ return console.log(err) } console.log('data:'+data.toString()) }) //异步写入文件 var data = { 'name' : 'yy', 'age' : '12', 'id' : '2018' } var dataText = JSON.stringify(data) var option = { encoding : 'utf8' , flag : 'w' } fs.writeFile('a.txt' ,dataText, option , function(err){ if(err){ console.log('write faild') }else{ console.log('write saved') } } )
同步
//同步读文件 file = fs.readFileSync(filePath , 'utf-8') //同步写入文件 fs.writeFileSync(filename, data[, options])
查看文件信息
fs.stat('../a.txt' , function(err , stats){ if(err){ console.log('failed') return 0; } console.log(stats) } //方法 stats.isFile() ; stats.isDirectory()
其他操作
//列出文件 fs.readdir(path , callback) //删除文件 fs.unlink(path , callback) //截断文件 fs.truncate(path , len , callback) 返回true和flase //创建目录 fs.mkdir(path , [mode] , callback) //删除目录 fs.rmkdir(path , callback)
2.2 构建一个 Web 服务器(http)
在 Node 中专门提供了一个核心模块:http ;http 这个模块的职责就是帮你编写服务器的。
//1.加载 http 核心模块
const http = require('http');
//2. 使用 http.createServer() 方法创建一个 Web 服务器;
// 返回一个实例
const server = http.createSever();
//3. 服务器要干嘛?
// 提供服务:对数据的服务
// 发请求
// 接受请求
// 处理请求
// 给个反馈
// 注册 request 请求事件
// 当客户端请求过来的时候,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
//requet 请求事件处理函数需要接收两个参数:
// Request 请求对象
// 请求对象可以用来获取客户端的一些请求信息,例如:请求路径
// Response 响应对象
// 响应对象可以用来给客户端发送信息
server.on('request',funtion (request,response) {
console.log('收到客户端的请求了,请求路径是:' + request.url);
console.log('请求我的客户端的地址是',request.socket.remoteAddress,request.socket.remotePort)
//response 对象有一个方法:write 可以用来给客户端发送响应数据
//write 可以使用多次,但是最后一定要用 end 来结束响应,否则客户端会一直等待
response.write('hello');
response.write('node.js');
//告诉客户端我的话说完了,你可以呈递给用户了
response.end();
//上面的方式比较麻烦
//可以直接用 response.end('hello node.js');
});
//4. 绑端口号,启动服务器
server.listen(3000,functiion () {
console.log('服务器启动成功,可通过 http://127.0.0.1:3000/ 来访问');
})
一个小栗子
const http = require('http');
const server = http.createSever();
server.on('request',funtion (req,res) {
const url = req.url;
if (url === '/products'){
const products = [
{
name:'苹果',
price:8888
},
{
name:'葡萄',
price:3000
},
{
name:'桃子',
price:4321
}
]
//响应内容只能是二进制数据或字符串
//中文会乱码
//在服务器默认发送的是数据,其实是 utf8 编码的内容
//但是浏览器不知道你是 utf8 编码的内容
//浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析,中文操作系统默认是 gbk
//解决方法,正确告诉浏览器我给你发送的内容是什么编码
res.setHeader('Content-Type','text/html',charset = utf-8)
res.end(JSON.stringfy(products));
}
}
server.listen(3000,function(){
console.log('服务器启动成功了,可以访问')
})
又是一个小栗子吖
var http = require('http')
var server = http.createServer((req,res)=>{
res.writeHead(200,{'Content-type':'text/html;charset=UTF-8'});
res.end("嘿嘿嘿,这是我的第一个Node页面")
});
server.listen(8080,'127.0.0.1');
console.log('Server is running at http://127.0.0.1:8080/');
一个大栗子
//server.js
//引入模块
const http = require('http')
//创建http服务器
const server = http.createServer((req , res)=>{
const {url , method } = req
console.log("url:%s,method:%s" , url , method)
//监听客户连接事件
req.on("connection" , (socket)=>{
console.log("客户端连接" , socket)
})
//接受传送数据
req.on("data", data=>{
console.log("recive data" , data)
})
req.on("end" ,()=>{
//返回数据
res.end('hello world')
})
})
//监听8000端口,等待连接
server.listen(8000 , ()=>{
console.log("server start")
})
//client.js
const http = require("http")
const postData = "test"
const options = {
hostname: 'localhost',
port: 8000,
path: '/',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应头: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`响应主体: ${chunk}`);
});
res.on('end', () => {
console.log('响应中已无数据');
});
});
req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`);
});
// 将数据写入请求主体。
req.write(postData);
req.end();
2.3 path和OS以及url
-
path
path.join
用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是"/
",Windows系统是"\
"。
console.log(path.join("/path" , "/user")); //\path\user
path.resolve
//path.resolve([from ...], to) //将 to 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径 console.log(path.resolve("" , "../")) //C:\Users\Administrator\Desktop console.log(path.resolve("" , "./")) //C:\Users\Administrator\Desktop\node-learn
-
OS
//用来获取机器信息的
const os = require('os');
//用来操作路径的
const path = require('path');
//获取当前机器的 CPU 信息
console.log(os.cpus())
//memory 内存
console.log(os.totalmem())
// extname extension name 扩展名
console.log(path.extname('c:/a/s/hello.txt')) //txt
- url
用来处理和解析url
的模块
//parse 用来解析url,返回url属性对象
const url = require("url")
const myURLA = url.parse('https://www.baidu.com/p/a/t/h?query=string#hash');
console.log(myURLA);
/**
Url {
protocol: 'https:', 协议
slashes: true,
auth: null, 用户密码
host: 'www.baidu.com', 主机名
port: null, 端口号
hostname: 'www.baidu.com', 主机名(不带端口号)
hash: '#hash', 哈希值
search: '?query=string', 查询字符串
query: 'query=string', 请求参数
pathname: '/p/a/t/h', 路径名
path: '/p/a/t/h?query=string', 带查询的路径名
href: 'https://www.baidu.com/p/a/t/h?query=string#hash' }
*/
2.4 模块系统
- 模块作用域
//a.js文件
//require就是一个方法,它的作用是用来加载核心模块
//相对路径必须加./
//在 Node 中,没有全局作用域,只有模块作用域
// 外部访问不到内部,内部也访问不到外部,都是封闭的
const foo = 'aaa';
console.log('a start');
function add (x,y) {
return x + y;
}
require('./b.js');
//可以省略后缀名,且推荐这种
//require('./b');
console.log('a end');
console.log('foo的值是':foo); //foo的值是:aaa
//b.js文件
consol.log('b start');
console.log(add(1+2)); //add is not undefined
const foo = 'bbb';
- 互相访问,加载与导出
我们加载文件模块的目的不是为了简简单单的执行里面的代码,更重要的是为了使用里的某个成员。
//require 方法有两个作用
// 1.加载文件模块并执行里面的代码
// 2.拿到被加载文件模块导出的接口对象
//
//在每个文件模块中都提供了一个对象: exports
//exports 默认是一个空对象
//你所要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中
//a.js文件
const ret = require('./b');
console.log(ret); //{}一个空对象
//b.js文件
const foo = 'bbb';
console.log(exports); //{}一个空对象
//a.js文件
const bExports = require('./b');
console.log(bExports); // {foo:hello}
console.log(bExports.foo); //hello
console.log(bExports.add(1 , 2)); //3,不是-1
//b.js文件
const foo = 'bbb';
//手动添加成员
exports.foo = hello;
exports.add = function (a,b) {
return a + b
}
function add (a,b) {
return a - b
}
const age = 18;
exports.age = age;
2.5 Web 服务器开发
- IP地址和端口号
- 端口号用来定位具体的应用程序
- 一切需要联网通信的软件都会占用一个端口号
- 端口号的范围为 0-65536之间
- 在计算机中有一些默认端口号,最好不要去使用,例如 HTTP 服务的 80
- 我们在开发过程中使用一些简单好记的就可以,例如3000、5000等没什么含义
- 可以同时开启多个服务,但是一定要确保不同的服务占用的端口号不一致才可以,其实就是在一台计算机中,同一个端口号同一时间只能被一个程序占用
2.6 简易的文件服务器
const http = require('http');
const fs = require('fs');
server.on('reuqest',function () {
// url: 同一资源定位符
//一个 url 最终其实是要对应到一个资源的
const url = req.url;
if (url === '/'){
fs.readFile('./resource/inidex.html',function (err,data){
if (err) {
res.setHeader('Content-Type','text/html',charset = utf-8);
//如果文件中是图片则:res.setHeader('Content-Type','image/jpeg')
res.end('文件读取失败,请稍后重试')
}else{
res.setHeader('Content-Type','text/html',charset = utf-8);
res.end(data);
}
})
}
})
//index.js
//引入http模块
const http = require('http'),
//引入url模块,解析url
URL = require('url'),
//读取文件
fileShow = require('./fs')
//创建一个http服务器
const server = http.createServer((req , res)=>{
const {url , method} = req
const {pathname} = URL.parse(url)
if(method === "GET"){
const data = fileShow("."+pathname).then((reslove , reject)=>{
if(!reslove) {
res.writeHead(404)
res.end("404 not found")
}
res.writeHead(200)
res.end(reslove)
})
}else{
res.writeHead(404)
res.end("404 not found")
}
})
server.listen(8000)
//fs.js
const fs = require('fs'),
//读取相关的文件
const fileShow = (pathname)=>{
//查看输入路由对应的是文件还是路由
return new Promise((reslove , reject)=>{
fs.stat(pathname , (err , status)=>{
if(err || !status.isFile()) reslove(false)
fs.readFile(pathname , "utf-8" , (err , data)=>{
if(err) reslove(false)
reslove(data)
})
})
})
}
module.exports = fileShow
3. 在Node中使用模板引擎
3.1 在浏览器中使用模板引擎
<body>
<!-- 在node.js中使用模板引擎 -->
<!-- art-template
注意:在浏览器中使用需要引用 lib/tempate-web.js <script src="node_modules/art-template/lib/template-web.js"></script>
强调:模板引擎不关心你的字符串内容,只关心自己能够认识的模板标记语法,例如 {{}};
{{}} 语法称之为 mustache 语法,八字胡
-->
<script src="node_modules/art-template/lib/template-web.js"></script>
<script type="text/template" id="tpl">
大家好,我叫:{{ name }}
我今年 {{ age }} 岁了
我来自 {{ province }}省
我喜欢:{{each hobbies}} {{ $value}} {{/each}}
</script>
<script>
let ret = template('tpl', {
name: 'jack',
age: '18',
province: "河南",
hobbies:[
'吃',
'喝',
'玩',
'乐'
]
})
console.log(ret);
</script>
</body>
3.2 在 node.js 中使用模板引擎
//在node.js中使用模板引擎
// art-template
// art-template 不仅可以在浏览器中使用,也可以在node中使用
// 安装:
// npm inatall art-template
// 该命令在哪执行就会把把包下载到哪里。默认会下载到node_modules 目录中
// node_modules 不要该,也不支持改
//1.安装 npm install art-template
//2.在需要使用的文件模板中加载art-template
// 只需要使用 require 方法就可以 : require('art-template');
// 参数中的 art-template 就是你下载包的名字
// 也就是说你的 install 的名字是什么,则你 require 中的就是什么
//3.查看文档。使用模板引擎的API
const template = require('art-template');
const fs = require('fs');
fs.readFile('./tpl.html'function (err,data) {
if (err) {
return console.log(''文件读取失败了)
}
//默认读到的 data 是二进制数据
//而模板引擎的 render 方法需要接收的是字符串
//所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用
const ret = template.render(data.tostring(),{
name: 'jack',
age: '18',
province: "河南",
hobbies:[
'吃',
'喝',
'玩',
'乐'
]
})
console.log('ret');
})
/*tpl.html文件*/
<p>大家好,我叫:{{ name }}</p>
<p>我今年 {{ age }} 岁了</p>
<p>我来自 {{ province }}省</p>
<p>我喜欢:{{each hobbies}} {{ $value}} {{/each}}</p>