使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http
var http = require("http");
使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。 函数通过 request, response 参数来接收和响应数据。
var http = require('http');
http.createServer(function(request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, { 'Content-Type': 'text/html;charset=UTF-8' });
// 发送响应数据 "第一个应用"
response.end('第一个应用\n');
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
使用 node 命令执行以上的代码:
node server.js
Server running at http://127.0.0.1:8888/
打开浏览器访问 http://127.0.0.1:8888/
node没有全局作用域。在Node.js中,通过require方法加载和执行多个JavaScript脚本文件。文件与文件之间由于是模块作用域,即使加载执行多个文件,可以完全避免变量命名冲突污染。但是某些情况下,模块与模块是需要进行通信的,可通过require方法得加载文件模块导出的接口对象。即:
在 Node.js 中,引入一个模块非常简单,如下我们创建一个 main.js 文件并引入 hello 模块
var hello = require('./hello');
hello.world();
以上实例中,代码 require(’./hello’) 引入了当前目录下的 hello.js 文件(./ 为当前目录,node.js 默认后缀为 js)
Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
接下来创建 hello.js 文件
exports.world = function() {
console.log('Hello 这是hello模块');
}
如果只是想把一个对象封装到模块中
代码格式如下:
module.exports = function() {
// ...
}
例如:
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('yy');
hello.sayHello();
模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports。
Node.js 中自带了一个叫做 http 的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量。
这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象
exports 和 module.exports 的使用
如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports。
不建议同时使用 exports 和 module.exports。
如果先使用 exports 对外暴露属性或方法,再使用 module.exports 暴露对象,会使得 exports 上暴露的属性或者方法失效。原因在于,exports 仅仅是 module.exports 的一个引用
path.normalize 不同系统的路径有可能不同,例如,Unix系统是 /,Windows系统是 \ 该方法可规范化路径
path.join 该方法path使用特定于平台的分隔符作为分隔符将所有给定的段连接在一起,然后对结果路径进行规范化
path.join('..', 'fs', '1', '1.txt'); // windows下:..\fs\1\1.txt
path.resolve( [from…], to ) 与 path.join 不同,前者只是简单的将路径段进行连接,而 path.resolve 会对路径段进行解析,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径
path.resolve('/foo/bar', './baz') // returns '/foo/bar/baz'
path.resolve('/foo/bar', 'baz') // returns '/foo/bar/baz'
path.resolve('/foo/bar', '/baz') // returns '/baz'
path.resolve('/foo/bar', '../baz') // returns '/foo/baz'
path.resolve('home','/foo/bar', '../baz') // returns '/foo/baz'
path.resolve('home','./foo/bar', '../baz') // returns '/home/foo/baz'
path.resolve('home','foo/bar', '../baz') // returns '/home/foo/baz'
path.resolve('home', 'foo', 'build','aaaa','aadada','../../..', 'asset') //return '/home/foo/asset'
path.isAbsolute 返回布尔值
path.isAbsolute(__dirname); // true
path.relative(from, to) 基于当前工作目录,返回从 from 到 to 的相对路径
path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb'); // ../../impl/bbb
path.basename(path[, ext]) 此方法区分大小写,包括扩展名
path.basename('/foo/bar/baz/asdf/quux.html'); // quux.html
path.basename('/foo/bar/baz/asdf/quux.html', '.html'); // quux
path.basename('/foo/bar/baz/asdf/quux.HTML', '.html'); // quux.HTML
path.parse('/home/user/dir/file.txt'); // { root: '/', dir: '/home/user/dir', base: 'file.txt', ext: '.txt', name: 'file' }
path.format({ root: '/', dir: '/home/user/dir', base: 'file.txt', ext: '.txt', name: 'file' }); // /home/user/dir/file.txt
fs是文件操作模块,跟数据库操作有些类似,大的方向为 - 增、删、改、查
区别:
const fs = require('fs'); // 文件操作
fs.writeFile('1.txt', '我是内容', err => {
if (err) return console.log(err);
console.log('写入成功');
});
fs.writeFile('1.txt', '我是内容', { flag: 'w' }, err => { });
fs.readFile('1.txt', 'utf-8', (err, data) => {
if (err) return console.log(err);
console.log(data);
});
fs.readFile('1.txt', (err, data) => { });
fs.copyFile('1.txt', '2.txt', err => {
if (err) return console.log(err);
console.log('复制成功');
});
fs.mkdir('1', err => {
if (err) return console.log(err);
console.log('创建成功');
});
fs.readdir('1', (err, data) => {
if (err) return console.log(err);
console.log(data);
});
function removeDir(_path) {
const data = fs.readdirSync(_path);
data.forEach(item => {
// 判断是否是文件 文件: 直接删除 目录:递归
// 注意:item是名称,需要组装完整路径: path.join(_path, item)
const url = path.join(_path, item);
if (fs.statSync(url).isFile()) {
// 文件: 直接删除
fs.unlinkSync(url);
} else {
// 目录:递归
removeDir(url)
}
});
// 删除空目录
fs.rmdirSync(_path);
}
removeDir('1');
http模块被用于服务器开发,简单来说,就是监听网络(端口),当有客户端请求了,那么就返回对应的数据
即根据模块标识来加载即:require('模块标识符')
1.自己写的模块
路径形式的模块:1./ 当前目录,不可省略 , 2../ 上一级目录,不可省略 3.js 后缀名可以省略
var b = require('./foo.js')
var b = require('./foo')
2.核心模块
核心模块的本质也是文件,已经被编译到了二进制文件中(下载后,编译在node.exe),我们只需要按照名字来加载就可以了
var http = require('http')
var fs = require('fs')
3.第三方模块
凡是第三方模块都必须通过 npm 来下载
使用的时候就可以通过 require('包名') 的方式来进行加载才可以使用
如: var template = require('art-template')
整个加载过程中:
先找到当前文件所处目录中的 node_modules 目录
node_modules/art-template
node_modules/art-template/
node_modules/art-template/package.json
node_modules/art-template/package.json 文件中的 main 属性
main 属性中就记录了 art-template 的入口模块
如果 package.json文件不存在或者main指定的入口模块是也没有,自动找该目录下的 index.js,index.js 是作为一个默认备选项
如果以上所有任何一个条件都不成立,进入上一级目录找 node_modules
按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx
一个项目有且仅有一个 node_modules 而且是存放到项目的根目录
- 优先从缓存加载:再次加载某个模块,不会执行里面的代码,但可以从缓存中拿到其中的接口对象,这样可以避免重复加载,提高模块加载效率
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
//EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的监听器时,newListener 事件会触发,当监听器被移除时,removeListener 事件被触发。
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);
// ---方法
// 1.addListener(event, listener) 为指定事件添加一个监听器到监听器数组的尾部
// 2.on(event, listener) 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
// 3.once(event, listener) 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
// 4.removeListener(event, listener) 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。它接受两个参数,第一个是事件名称,第二个是回调函数名称
// 5.removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
// 6.setMaxListeners(n) 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于改变监听器的默认限制的数量。
// 7.listeners(event) 返回指定事件的监听器数组。
// 8.emit(event, [arg1], [arg2], [...]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
// ---类方法 获取事件的监听器数量 events.emitter.listenerCount(eventName);
// ---事件 newListener removeListener 从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。
Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。
Node.js,Stream 有四种流类型:
所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:
var data = '';
var fs = require('fs');
// 创建可读流
var readStream = fs.createReadStream('input.txt');
// 设置编码为 utf8。
readStream.setEncoding('UTF8');
// 处理流事件 --> data, end, and error
readStream.on('data', function(chunk) {
data += chunk;
});
readStream.on('end', function() {
console.log(data + '流 文件读取');
});
readStream.on('error', function(err) {
console.log(err.stack);
});
console.log('流 文件读取完毕');
var outputData = '流 写入文件-----';
var writeStream = fs.createWriteStream('output.txt');
writeStream.write(outputData, 'UTF8');
writeStream.end();
writeStream.on('finish', function() {
console.log('写入完成');
});
writeStream.on('error', function(err) {
console.log(err.stack);
});
console.log('流 文件写入完毕');
管道流 管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。
// 管道读写操作
// 创建一个可读流
var fs = require('fs');
var readerStream = fs.createReadStream('input.txt');
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
var writerStream = fs.createWriteStream('pipeStream.txt');
readerStream.pipe(writerStream);
链式流 链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。
var fs = require('fs');
var zlib = require('zlib');
fs.createReadStream('input.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('input.txt.gz'));
console.log('文件压缩完成');
fs.createReadStream('input.txt.gz').pipe(zlib.createGunzip()).pipe(fs.createWriteStream('input.txt'));
console.log('文件解压完成');