一.Nodejs介绍
- Node.js是什么?
Node.js 诞生于 2009 年,由 Joyent 的员工 Ryan Dahl 开发而成, 目前官网最新版本已经更新到 12.0.0版本,最新稳定的是10.15.3。Node.js 不是一门语言也不是框架,它只是基于 Google V8 引擎的 JavaScript 运行时环境,同时结合 Libuv 扩展了 JavaScript 功能,使之支持 io、fs 等只有语言才有的特性,使得 JavaScript 能够同时具有 DOM 操作(浏览器)和 I/O、文件读写、操作数据库(服务器端)等能力,是目前最简单的全栈式语言。
这里我们可以简单理解Node.js是一个内置有chrome V8引擎的JavaScript运行环境,他可以使原本在浏览器中运行的JavaScript有能力跑后端,从而操作我们数据库,进行文件读写等。
目前市面上高密集的I/O模型,比如 Web 开发,微服务,前端构建等都有做Node.js的身影。不少大型网站都是使用 Node.js 作为后台开发语言的,比如 淘宝 双十去哪儿网 的 PC 端核心业务等。另外我们一些前端工具譬如VSCode,webpack等也是有Node.js开发。
Node.js的包管理工具,npm已经成为世界开源包管理中最大的生态,功能强大,目前单月使用者接近1000万。
2.Node.js 是一个 Javascript 运行环境(runtime)。它让 JavaScript 可以开发后端程序, 它几乎能实现其他后端语言能实现的所有功能。
3.Node.js使得JavaScript可以脱离浏览器的窗口,独立运行在Node.js提供的环境中,所以Node.js中没有BOM,DOM这些概念。Node.js中根本没有页面,主要是进行一些服务器上的操作(比如:读写文件,网络通信…)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NysbfHbj-1598271260898)(https://i.loli.net/2020/08/22/ftQ9Y32wvSsMrmV.png)]
二.Node.js模块化的理解
Node.js采用的是CommonJs规范,在NodeJS中,一般将代码合理拆分到不同的JS文件中,每一个文件就是一个模块,而文件路径就是模块名。 在编写每个模块时,都有require、exports、module三个预先定义好的变量可供使用。
Node.js中模块的分类:
- 核心模块(已经封装好的内置模块);
- 自己定义的模块;
- 第三方的模块(npm下载下来的);
- require
require
函数用来在一个模块中引入另外一个模块。传入一个模块名,返回一个模块导出对象。用法:let cc = require("模块名")
,其中模块名可以用绝对路径也可以用相对路径,模块的后缀名.js可以省略。例如:
let cc1 = require('./main.js')
let cc2 = require('home/src/main.js')
let cc3 = require('./main')
require()函数用两个作用:
- 执行导入的模块中的代码;
- 返回导入模块中的接口对象;
2.exports
exports
对象用来导出当前模块的公共方法或属性,别的模块通过require
函数使用当前模块时得到的就是当前模块的exports
对象。用法:exports.name
,name为导出的对象名。例子:
exports.add = function () {
let i = 0
console.log(++i)
}
导出一个add方法供其他模块使用
其实exports类似于ES6中的export的用法,用来导出一个指定名字的对象。
3.module.exports
module.exports
用来导出一个默认对象,没有指定对象名,常见于修改模块的原始导出对象。比如原本模块导出的是一个对象,我们可以通过module.exports修改为导出一个函数。如下:
module.exports = function () {
console.log('hello world!')
}
三.Node.js中module.exports和exports的区别
Node中,每个模块都有一个exports
接口对象,我们需要把公共的方法或者字符串挂载在这个接口对象中,其他的模块才可以使用。
Node.js中只有模块作用域,默认两个模块之间的变量,方法互不冲突,互不影响,这样就导致一个问题,我们怎样使用加载进来的模块中的方法呢?这就需要在另外一个模块
exports
接口对象中挂载模块中公共的方法。
-
Node中每个模块都有一个
module
对象,module
对象中的有一个exports
属性为一个接口对象,我们需要把模块之间公共的方法或属性挂载在这个接口对象中,方便其他的模块使用这些公共的方法或属性。 -
Node中每个模块的最后,都会
return module.exports
(nodejs底层的代码)。 -
Node中每个模块都会把
module.exports
指向的对象赋值给一个变量exports
,也就是说:var exports = module.exports
。 -
module.exports = XXX
,表示当前模块导出一个单一成员,结果就是XXX。 -
如果需要导出多个成员时必须使用
exports.add = XXX; exports.foo = XXX;
或者使用module.exports.add = XXX; module.export.foo = XXX;
,
四.NodeJs中HTTP模块、URL模块
const http =require('http');
const url =require('url');
/*
req 获取客户端传过来的信息
res 给浏览器响应信息
*/
http.createServer((req,res)=>{
//http://127.0.0.1?name=zhangsan&age=20 想获取url传过来的name 和age
//设置响应头
//状态码是 200,文件类型是 html,字符集是 utf-8
res.writeHead(200,{"Content-type":"text/html;charset='utf-8'"}); //解决乱码
res.write("<head> <meta charset='UTF-8'></head>"); //解决乱码
console.log(req.url); //获取浏览器访问的地址
if(req.url!='/favicon.ico'){
var userinfo=url.parse(req.url,true).query;
console.log(`姓名:${userinfo.name}--年龄:${userinfo.age}`);
}
res.end('你好nodejs'); //结束响应
}).listen(3000);
五.NodeJs中fs模块
// 1. 结合 fs 发送文件中的数据
// 2. Content-Type
// http://tool.oschina.net/commons
// 不同的资源对应的 Content-Type 是不一样的
// 图片不需要指定编码
// 一般只为字符数据才指定编码
var http = require('http')
var fs = require('fs')
var server = http.createServer()
server.on('request', function (req, res) {
// / index.html
var url = req.url
if (url === '/') {
// res.end('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body><h1>首页</h1></body></html>')
//我们要发送的还是在文件中的内容
fs.readFile('./resource/index.html', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('文件读取失败,请稍后重试!')
} else {
// data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
// res.end() 支持两种数据类型,一种是二进制,一种是字符串
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(data)
}
})
} else if (url === '/xiaoming') {
// url:统一资源定位符
// 一个 url 最终其实是要对应到一个资源的
fs.readFile('./resource/ab2.jpg', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('文件读取失败,请稍后重试!')
} else {
// data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
// res.end() 支持两种数据类型,一种是二进制,一种是字符串
// 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码
res.setHeader('Content-Type', 'image/jpeg')
res.end(data)
}
})
}
})
server.listen(3000, function () {
console.log('Server is running...')
})
/*
1. fs.stat 检测是文件还是目录
2. fs.mkdir 创建目录
3. fs.writeFile 创建写入文件
4. fs.appendFile 追加文件
5. fs.readFile 读取文件
6. fs.readdir读取目录
7. fs.rename 重命名 移动文件
8. fs.rmdir 删除目录
9. fs.unlink 删除文件
*/
六.art-template模板引擎
art-template 是一个简约、超快的模板引擎。它采用作用域预声明的技术来优化模板渲染速度,从而获得接近 JavaScript 极限的运行性能,并且同时支持 NodeJS 和浏览器。
1.输出
{{value}}
{{data.key}}
{{data['key']}}
{{a ? b : c}}
{{a || b}}
{{a + b}}
2.条件输出
<!-- 单 if 判断 -->
{{if value}}
...
{{/if}}
<!-- if ... else ... 判断 -->
{{if v1}}
...
{{else if v2}}
...
{{/if}}
3.循环输出
{{each target}}
{{$index}} {{$value}}
{{/each}}
//target是一个数组,each用于对数组遍历,$index 是数组的下标, $value是数组的值原始语法
案例
var template = require('art-template')
var fs = require('fs')
// 这里不是浏览器
// template('script 标签 id', {对象})
// var tplStr = `
// <!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8">
// <title>Document</title>
// </head>
// <body>
// <p>大家好,我叫:{{ name }}</p>
// <p>我今年 {{ age }} 岁了</p>
// <h1>我来自 {{ province }}</h1>
// <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
// </body>
// </html>
// `
fs.readFile('./tpl.html', function (err, data) {
if (err) {
return console.log('读取文件失败了')
}
// 默认读取到的 data 是二进制数据
// 而模板引擎的 render 方法需要接收的是字符串
// 所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用
var ret = template.render(data.toString(), {
name: 'Jack',
age: 18,
province: '北京市',
hobbies: [
'写代码',
'唱歌',
'打游戏'
],
title: '个人信息'
})
console.log(ret)
})
七.管道流
管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。
如上面的图片所示,我们把文件比作装水的桶,而水就是文件里的内容,我们用一根管子(pipe)连接两个桶使得水从一个
桶流入另一个桶,这样就慢慢的实现了大文件的复制过程。
以下实例我们通过读取一个文件内容并将内容写入到另外一个文件中。
var fs = require("fs"); // 创建一个可读流
var readStream = fs.createReadStream('input.txt'); // 创建一个可写流
var writeStream = fs.createWriteStream('output.txt');
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readStream.pipe(writeStream);
console.log("程序执行完毕");
写入到另外一个文件中。
var fs = require("fs"); // 创建一个可读流
var readStream = fs.createReadStream('input.txt'); // 创建一个可写流
var writeStream = fs.createWriteStream('output.txt');
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readStream.pipe(writeStream);
console.log("程序执行完毕");