node.js基础之api概述

152 阅读6分钟

一、简介

Node是JavaScript语言的服务器运行环境。所谓“运行环境”有两层意思:首先,JavaScript语言通过Node在服务器运行,其次,Node提供大量工具库,使得JavaScript语言与操作系统互动(比如读写文件、新建子进程),在这个意义上,Node又是JavaScript的工具库。
node.js特性其实是JS的特性:事件驱动、非阻塞I/O。

二、Buffer对象

1.概述

Buffer是node处理二进制数据的接口,为全局对象,不需要引入。是一个构造函数,生成一个类似数组的对象。

var bytes = new Buffer(256);

2.创建 Buffer 类

  • Buffer.alloc(size[, fill[, encoding]]),返回一个指定大小的 Buffer 实例,如果没有设置 fill,则默认填满 0。
// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1)
  • Buffer.concat(list[, totalLength]),返回一个新值Buffer,该值是将所有Buffer 实例连接list在一起的结果。
  • Buffer.from(array),返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
  • Buffer.from(string[, encoding]),将string转换为buffer。
  • buf.write(string[, offset[, length]][, encoding]),写入缓冲区,返回实际写入的大小。
buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");
  • buf.toString([encoding[, start[, end]]]),读取 Node 缓冲区数据。返回值:解码缓冲区数据并使用指定的编码返回字符串。
const buf = Buffer.alloc(10,'123');
buf.write('jucious')
console.log(buf.toString())
//新写入的字符会覆盖之前的
  • Buffer.concat(list[, totalLength])
var buffer1 = Buffer.from(('菜鸟教程'));
var buffer2 = Buffer.from(('www.runoob.com'));
var buffer3 = Buffer.concat([buffer1,buffer2]);

三、EventEmitter

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。

  • EventEmitter 类
    events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
    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); 

四、Stream(流)

  • 概述
    ”数据流“(stream)是处理系统缓存的一种方式。操作系统采用数据块(chunk)的方式读取数据,每收到一次数据,就存入缓存。Node应用程序有两种缓存的处理方式,第一种是等到所有数据接收完毕,一次性从缓存读取,这就是传统的读取文件的方式;第二种是采用“数据流”的方式,收到一块数据,就读取一块,即在数据还没有接收完成时,就开始处理它。
    数据流接口最大特点就是通过事件通信,具有readable、writable、drain、data、end、close等事件,既可以读取数据,也可以写入数据。读写数据时,每读入(或写入)一段数据,就会触发一次data事件,全部读取(或写入)完毕,触发end事件。如果发生错误,则触发error事件。
    一个对象只要部署了数据流接口,就可以从它读取数据,或者写入数据。Node内部很多涉及IO处理的对象,都部署了Stream接口,例如:文件读写、HTTP 请求的读写、TCP 连接、标准输入输出。
  • 从流中读取数据
    fs.createReadStream方法就是以”数据流“的方式读取文件,这可以在文件还没有读取完的情况下,就输出到标准输出。这显然对大文件的读取非常有利。
var fs = require("fs");
var data = '';
// 创建可读流
var readerStream = fs.createReadStream('input.txt');
// 设置编码为 utf8。
readerStream.setEncoding('UTF8');
// 处理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});
readerStream.on('end',function(){
   console.log(data);
});
  • 写入流
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据
writerStream.write('hello','UTF8');
// 表示不再将数据写入Writable。
writerStream.end();
// 处理流事件 --> data, end, and error
writerStream.on('finish', function() {
    console.log("写入完成。");
});
  • 管道流
    管道提供了一个输出流到输入流的机制,通常我们用于从一个流中获取数据并将数据传递到另外一个流中。
    如上面的图片所示,我们把文件比作装水的桶,而水就是文件里的内容,我们用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程
    语法:readable.pipe(destination[, options])该readable.pipe()方法将Writable流附加到readable。
// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');
// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);
  • 链式流
var fs = require("fs");
var zlib = require('zlib');
// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));

五、全局对象

Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

  • __filename
    __filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。如果在模块中,返回的值是模块文件的路径。
  • __dirname
    __dirname 表示当前执行脚本所在的目录。
  • process
    用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。

六、fs模块

  • readFile(),readFileSync()
var fs = require("fs")
//异步读取
fs.readFile('input.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }
   console.log("异步读取: " + data.toString());
});
// 同步读取
var data = fs.readFileSync('input.txt');
  • writeFile(),writeFileSync()
//异步 在回调函数之前可以加编码
fs.writeFile('message.txt', 'Hello Node.js', (err) => {
  if (err) throw err;
  console.log('It\'s saved!');
});
//同步
fs.writeFileSync(fileName, str, 'utf8');
  • mkdir()
    mkdir方法用于新建目录。mkdir接受三个参数,第一个是目录名,第二个是权限值,第三个是回调函数。
var fs = require('fs');
fs.mkdir('./helloDir',0777, function (err) {
  if (err) throw err;
});

  • readdir()
    eaddir方法用于读取目录,返回一个所包含的文件和子目录的数组。
  • 打开文件
    以下为在异步模式下打开文件的语法格式:fs.open(path, flags[, mode], callback),flags - 文件打开的行为。
var fs = require("fs");
// 异步打开文件
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
  console.log("文件打开成功!");     
});
  • stat()
    fs.stat(path, callback),callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。
var fs = require('fs');
fs.stat('/Users/liuht/code/itbilu/demo/fs.js', function (err, stats) {
    console.log(stats.isFile());         //true
})
  • watchfile(),unwatchfile()
    watchfile方法监听一个文件,如果该文件发生变化,就会自动触发回调函数。
var fs = require('fs');
fs.watchFile('./testFile.txt', function (curr, prev) {
  console.log('the current mtime is: ' + curr.mtime);
  console.log('the previous mtime was: ' + prev.mtime);
});
fs.writeFile('./testFile.txt', "changed", function (err) {
  if (err) throw err;
  console.log("file write complete");   
});

unwatchfile方法用于解除对文件的监听。

  • createReadStream()
    createReadStream方法往往用于打开大型的文本文件,创建一个读取操作的数据流。所谓大型文本文件,指的是文本文件的体积很大,读取操作的缓存装不下,只能分成几次发送,每次发送会触发一个data事件,发送结束会触发end事件。(具体代码见四、Stream(流))
  • createWriteStream()
    createWriteStream方法创建一个写入数据流对象,该对象的write方法用于写入数据,end方法用于结束写入操作。(具体代码见四、Stream(流)) createWriteStream方法和createReadStream方法配合,可以实现拷贝大型文件。
function fileCopy(filename1, filename2, done) {
  var input = fs.createReadStream(filename1);
  var output = fs.createWriteStream(filename2);
  input.on('data', function(d) { output.write(d); });
  input.on('error', function(err) { throw err; });
  input.on('end', function() {
    output.end();
    if (done) done();
  });
}

七、Web 模块

1.基本用法

1.1 处理get请求

var http = require('http');
var fs = require('fs');
//调用http模块的createServer方法,创造一个服务器实例
http.createServer(function (request, response){
<!--方式一-->
  fs.readFile('data.txt', function readData(err, data) {
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end(data);
  });
  <!--方式二-->
  fs.createReadStream(`${__dirname}/index.html`).pipe(response);
}).listen(8080, '127.0.0.1');

response.end方法用来写入HTTP回应的具体内容,以及回应完成后关闭本次对话。

1.2request对象

createServer方法的回调函数的第一个参数是一个request对象,拥有属性:url:发出请求的网址;method:HTTP请求的方法;headers:HTTP请求的所有HTTP头信息。

  • 获取请求的路径名
var url = require('url');
var pathname = url.parse(request.url).pathname;
  • setEncoding()方法用于设置请求的编码。
request.setEncoding("utf8");

1.3 处理post请求

//例如表单提交post请求
var http = require('http');
http.createServer(function (req, res) {
  var content = "";
  req.on('data', function (chunk) {
    content += chunk;
  });
  req.on('end', function () {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("You've sent: " + content);
    res.end();
  });

}).listen(8080);

data事件会在数据接收过程中,每收到一段数据就触发一次,接收到的数据被传入回调函数。end事件则是在所有数据接收完成后触发。 对上面代码稍加修改,就可以做出文件上传的功能。

http.createServer(function (request, response) {
  response.writeHead(200);
  file = fs.createWriteStream("destination.md");
  request.pipe(file);
  fileSize = request.headers['content-length'];
  uploadedBytes = 0;
  request.on('data', function (d) {
    uploadedBytes += d.length;
    var p = (uploadedBytes / fileSize) * 100;
    response.write("Uploading " + parseInt(p, 0) + " %\n");
  });
  request.on('end', function () {
    response.end("File Upload Complete");
  });
}).listen(3030, function () {
  console.log("server started");
});

2.发出请求

2.1 get()

function getMsg(callback) {
  return http.get({
    host: 'personatestuser.org',
    path: '/email'
  }, function(response) {
    var data = '';
    response.on('data', function(d) {
      data += d;
    });
    response.on('end', function() {
      var parsed = JSON.parse(data);
      callback({
        email: parsed.email,
        password: parsed.pass
      });
    });
  });
},

2.2 post()

equest方法用于发出HTTP请求,它的使用格式:http.request(options[, callback]). 下面是发送POST请求的一个例子。

const postData = querystring.stringify({
  'msg': '你好世界'
});
const options = {
  hostname: 'nodejs.cn',
  port: 80,
  path: '/upload',
  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();