nodejs学习笔记

  1. nodejs创建服务器

http.createServer(),response.writeHead(),response.end()

var http = require('http');
 
http.createServer(function (request, response) {
 
    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {'Content-Type': 'text/plain'});
 
    // 发送响应数据 "Hello World"
    response.end('Hello World\n');
}).listen(8888);
 
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

 

 

  1. nodejs回调函数

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。

我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。

(1)阻塞代码实例:

var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());

console.log("程序执行结束!");

执行结果如下:

$ node main.js
菜鸟教程官网地址:www.runoob.com
 
程序执行结束!

(2)非阻塞代码实例:

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {

    if (err) return console.error(err);

    console.log(data.toString());

});

console.log("程序执行结束!");

$ node main.js

程序执行结束!

菜鸟教程官网地址:www.runoob.com

第一个实例在文件读取完后才执行完程序。,第二个实例我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。因此,阻塞是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

 

 

  1. Nodejs事件循环

(1)事件驱动程序

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。Node.js 几乎每一个 API 都是支持回调函数的。Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。

Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

 

执行结果如下:

$ node main.js
连接成功。
数据接收成功。
程序执行完毕。

 

(2)Node 应用程序是如何工作的?

在 Node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

 

 

  1. EventEmitter

    Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

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

  1. EventEmitter类

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。

    EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的监听器时,newListener 事件会触发,当监听器被移除时,removeListener 事件被触发。

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); 

执行结果如下:

$ node event.js 
some_event 事件触发

运行这段代码,1 秒后控制台输出了 'some_event 事件触发'。其原理是 event 对象注册了事件 some_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的监听器。

 

EventEmitter 提供了多个属性,如 on 和 emit。on 函数用于绑定事件函数emit 属性用于触发一个事件。

 

  1. 继承EventEmitter

    大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

为什么要这样做呢?原因有两点:

首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发生应该是一个对象的方法。

其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。

 

 

  1. Buffer(缓冲区)

    JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

    每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

    在v6.0之前创建Buffer对象直接使用new Buffer()构造函数来创建对象实例,但是Buffer对内存的权限操作相比很大,可以直接捕获一些敏感信息,所以在v6.0以后,官方文档里面建议使用 Buffer.from() 接口去创建Buffer对象。

  1. 写入缓冲区

buf.write(string[, offset[, length]][, encoding])

根据 encoding 的字符编码写入 string 到 buf 中的 offset 位置。 length 参数是写入的字节数。 如果 buf 没有足够的空间保存整个字符串,则只会写入 string 的一部分。 只部分解码的字符不会被写入。返回实际写入的长度。

  1. 从缓冲区读取数据
buf.toString([encoding[, start[, end]]])
  1. 将Buffer转换为JSON对象
buf.toJSON()

(4)缓冲区合并

Buffer.concat(list[, totalLength])

(5)缓冲区比较

buf.compare(otherBuffer);

(6)拷贝缓冲区

buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])

(7)缓冲区裁剪

buf.slice([start[, end]])

 

 

  1. Stream(流)

Stream 有四种流类型:

Readable - 可读操作。

Writable - 可写操作。

Duplex - 可读可写操作.

Transform - 操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

data - 当有数据可读时触发。

end - 没有更多的数据可读时触发。

error - 在接收和写入过程中发生错误时触发。

finish - 所有数据已被写入到底层系统时触发。

(1)从流中读取数据

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);

});

 

readerStream.on('error', function(err){

   console.log(err.stack);

});

 

console.log("程序执行完毕");

(2)写入流

var fs = require("fs");

var data = '菜鸟教程官网地址:www.runoob.com';

 

// 创建一个可以写入的流,写入到文件 output.txt

var writerStream = fs.createWriteStream('output.txt');

 

// 使用 utf8 编码写入数据

writerStream.write(data,'UTF8');

 

// 标记文件末尾

writerStream.end();

 

// 处理流事件 --> data, end, and error

writerStream.on('finish', function() {

    console.log("写入完成。");

});

 

writerStream.on('error', function(err){

   console.log(err.stack);

});

 

console.log("程序执行完毕");

(3)管道流(src.pipe(dest))

var fs = require("fs");

 

// 创建一个可读流

var readerStream = fs.createReadStream('input.txt');

 

// 创建一个可写流

var writerStream = fs.createWriteStream('output.txt');

 

// 管道读写操作

// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中

readerStream.pipe(writerStream);

 

console.log("程序执行完毕");

(4)链式流

链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

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'));

 

console.log("文件压缩完成。");

 

 

  1. 模块系统

(1)从文件模块缓存中加载

尽管原生模块与文件模块的优先级不同,但是都会优先从文件模块的缓存中加载已经存在的模块。

(2)从原生模块加载

原生模块的优先级仅次于文件模块缓存的优先级。require 方法在解析文件名之后,优先检查模块是否在原生模块列表中。以http模块为例,尽管在目录下存在一个 http/http.js/http.node/http.json 文件,require("http") 都不会从这些文件中加载,而是从原生模块中加载。

原生模块也有一个缓存区,同样也是优先从缓存区加载。如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。

(3)从文件加载

当文件模块缓存中不存在,而且不是原生模块的时候,Node.js 会解析 require 方法传入的参数,并从文件系统中加载实际的文件

 

 

 

 

 

  1. Nodejs函数

匿名函数:

    我们可以把一个函数作为变量传递。但是我们不一定要绕这个"先定义,再传递"的圈子,我们可以直接在另一个函数的括号中定义和传递这个函数

function execute(someFunction, value) {

  someFunction(value);

}

 

execute(function(word){ console.log(word) }, "Hello");

 

 

  1. 路由

    为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。因此,我们需要查看 HTTP 请求,从中提取出请求的 URL 以及 GET/POST 参数。这一功能应当属于路由还是服务器(甚至作为一个模块自身的功能)确实值得探讨,但这里暂定其为我们的HTTP服务器的功能。

var server = require("./server");

var router = require("./router");

server.start(router.route);

 

 

  1. 全局对象

全局变量与全局对象:

    global 最根本的作用是作为全局变量的宿主。按照 ECMAScript 的定义,满足以下条 件的变量是全局变量:

  1. 在最外层定义的变量;
  2. 全局对象的属性;
  3. 隐式定义的变量(未定义直接赋值的变量)。

当你定义一个全局变量时,这个变量同时也会成为全局对象的属性,反之亦然。需要注 意的是,在 Node.js 中你不可能在最外层定义变量,因为所有用户代码都是属于当前模块的, 而模块本身不是最外层上下文。

注意: 最好不要使用 var 定义变量以避免引入全局变量,因为全局变量会污染命名空间,提高代码的耦合风险。

__filename:表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。

__dirname:表示当前执行脚本所在的目录。

process:是一个全局变量,即 global 对象的属性。它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。

 

 

  1. 文件系统

var fs = require("fs")

(1)同步和异步

Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。

异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。

建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。

实例:

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');
console.log("同步读取: " + data.toString());
 
console.log("程序执行完毕。");

 

(2)打开文件

在异步模式下打开文件的语法格式:

fs.open(path, flags[, mode], callback)

var fs = require("fs");
 
// 异步打开文件
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
  console.log("文件打开成功!");     
});

 

(3)获取文件信息

    通过异步模式获取文件信息的语法格式:fs.stat(path, callback)

var fs = require('fs');
 
fs.stat('/Users/liuht/code/itbilu/demo/fs.js', function (err, stats) {
    console.log(stats.isFile());         //true
})

 

  1. 读写文件

异步模式下读取文件的语法格式:

fs.read(fd, buffer, offset, length, position, callback)

    异步模式下写入文件的语法格式:

fs.writeFile(file, data[, options], callback)

var fs = require("fs");
 
console.log("准备写入文件");
fs.writeFile('input.txt', '我是通 fs.writeFile 写入文件的内容',  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("数据写入成功!");
   console.log("--------我是分割线-------------")
   console.log("读取写入的数据!");
   fs.readFile('input.txt', function (err, data) {
      if (err) {
         return console.error(err);
      }
      console.log("异步读取文件数据: " + data.toString());
   });
});

 

  1. 关闭文件

    异步模式下关闭文件的语法格式:fs.close(fd, callback)

var fs = require("fs");
var buf = new Buffer.alloc(1024);
 
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
   console.log("文件打开成功!");
   console.log("准备读取文件!");
   fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
      if (err){
         console.log(err);
      }
 
      // 仅输出读取的字节
      if(bytes > 0){
         console.log(buf.slice(0, bytes).toString());
      }
 
      // 关闭文件
      fs.close(fd, function(err){
         if (err){
            console.log(err);
         } 
         console.log("文件关闭成功");
      });
   });
});

 

(6)截取文件

    异步模式下截取文件的语法格式:fs.ftruncate(fd, len, callback)

var fs = require("fs");
var buf = new Buffer.alloc(1024);
 
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
   console.log("文件打开成功!");
   console.log("截取10字节内的文件内容,超出部分将被去除。");
   
   // 截取文件
   fs.ftruncate(fd, 10, function(err){
      if (err){
         console.log(err);
      } 
      console.log("文件截取成功。");
      console.log("读取相同的文件"); 
      fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
         if (err){
            console.log(err);
         }
 
         // 仅输出读取的字节
         if(bytes > 0){
            console.log(buf.slice(0, bytes).toString());
         }
 
         // 关闭文件
         fs.close(fd, function(err){
            if (err){
               console.log(err);
            } 
            console.log("文件关闭成功!");
         });
      });
   });
});

 

(7)删除文件

删除文件的语法格式:fs.unlink(path, callback)

var fs = require("fs");
 
console.log("准备删除文件!");
fs.unlink('input.txt', function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("文件删除成功!");
});

 

 

  1. GET与POST

(1)通过GET获取URL参数

 

(2)获取POST请求内容

 

 

 

  1. Web模块

    Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL,与客户端的网络浏览器配合。

大多数 web 服务器都支持服务端的脚本语言(php、python、ruby)等,并通过脚本语言从数据库获取数据,将结果返回给客户端浏览器。

目前最主流的三个Web服务器是Apache、Nginx、IIS。

 

以下是演示一个最基本的 HTTP 服务器架构(使用 8080 端口),创建 index.html与server.js文件,代码如下所示:

 

 

 

 

  1. RESTful API

    REST即表述性状态传递(英文:Representational State Transfer,简称REST),表述性状态转移是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML(标准通用标记语言下的一个子集)以及HTML(标准通用标记语言下的一个应用)这些现有的广泛流行的协议和标准。REST 通常使用 JSON 数据格式

(1)RESTful Web Services

基于 REST 架构的 Web Services 即是 RESTful。

由于轻量级以及通过 HTTP 直接传输数据的特性,Web 服务的 RESTful 方法已经成为最常见的替代方法。可以使用各种语言(比如 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])实现客户端。

RESTful Web 服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的 Web 浏览器构建一个 GET URL 并读取返回的内容。

    RESTful详解: https://www.runoob.com/w3cnote/restful-architecture.html

  1. 表述性转态转移,即资源状态转移

URI (标识、定位任何资源的字符串)例子:

https://github.com/git/git

https://github.com/git/git/blob/master/block-sha1/sha1.h

https://github.com/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08

https://github.com/git/git/pulls

https://github.com/git/git/pulls?state=closed

https://github.com/git/git/compare/master…next

URI设计技巧:使用_或-来让URI可读性更好、使用/来表示资源的层级关系、使用/来表示资源的层级关系、,或;可以用来表示同级资源的关系。

  1. 统一资源接口

    RESTful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。

如果按照HTTP方法的语义来暴露资源,那么接口将会拥有安全性和幂等性的特性,例如GET和HEAD请求都是安全的, 无论请求多少次,都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的(POST不幂等),无论对资源操作多少次, 结果总是一样的,后面的请求并不会产生比第一次更多的影响。

GET POST PUT DELETE响应码:

301(Moved Permanently) - 资源的URI已被更新

303(See Other) - 其他(如,负载均衡)

304(not modified)- 资源未更改(缓存)

400 (bad request)- 指代坏请求(如,参数错误)

404 (not found)- 资源不存在

406 (not acceptable)- 服务端不支持所需表示

500 (internal server error)- 通用错误响应

503 (Service Unavailable)- 服务端当前无法处理请求

(还需加强对RESTful的理解)

 

 

 

 

 

 

 

 

 

  1. Node.js 连接 MongoDB

npm install mongodb

 

  1. 创建数据库

 

 

  1. 创建集合

 

 

  1. 数据库操作(CRUD)
  1. insertOne

 

  1. insertMany

 

  1. find

 

 

  1. updateOne

 

  1. updateMany

 

  1. deleteOne

 

  1. deletMany

 

  1. sort
  1. { type: 1 }  // type 字段升序
  1. { type: -1 } // type 字段降序

 

i.limit

如果要设置指定的返回条数可以使用 limit() 方法,该方法只接受一个参数,指定了返回的条数。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值