Node.js指南,第10部分:标准模块,流,数据库,NODE_ENV

本材料总结了Node.js手动翻译系列。 今天,我们将讨论os,事件和http模块,讨论使用流和数据库,并讨论在应用程序开发和生产中使用Node.js。




Node.js OS模块


os模块提供对许多功能的访问,这些功能可用于获取有关运行Node.js的计算机的操作系统和硬件的信息。 这是一个标准模块,您不需要安装它,就可以通过代码使用它,只需将其连接即可:

 const os = require('os') 

这里有几个有用的属性,尤其是在处理文件时可能会派上用场。

因此, os.EOL属性使os.EOL可以找出系统中使用的行分隔符(行os.EOL )。 在Linux和macOS上,这是\n ,在Windows上是\r\n

应该注意的是,当我们在这里提到“ Linux和macOS”时,我们所谈论的是POSIX兼容平台。 为了简洁起见,我们在这里不会提及不太受欢迎的平台。

os.constants.signals属性提供有关用于处理过程信号(如SIGHUPSIGKILL等)的常量的信息。 在这里您可以找到有关它们的详细信息。

os.constants.errno属性包含用于错误消息的常量,例如EADDRINUSEEOVERFLOW

现在考虑os模块的主要方法。

▍os.arch()


此方法返回一个标识系统体系结构的字符串,例如armx64arm64

▍os.cpus()


返回有关系统中可用处理器的信息。 例如,此信息可能如下所示:

 [ { model: 'Intel(R) Core(TM)2 Duo CPU     P8600 @ 2.40GHz',   speed: 2400,   times:    { user: 281685380,      nice: 0,      sys: 187986530,      idle: 685833750,      irq: 0 } }, { model: 'Intel(R) Core(TM)2 Duo CPU     P8600 @ 2.40GHz',   speed: 2400,   times:    { user: 282348700,      nice: 0,      sys: 161800480,      idle: 703509470,      irq: 0 } } ] 

▍os.endianness()


根据用来编译Node.js二进制文件的字节顺序 (Big Engian或Little Endian)返回BELE

▍os.freemem()


返回可用系统内存量(以字节为单位)。

▍os.homedir()


返回当前用户主目录的路径。 例如, '/Users/flavio'

▍os.hostname()


返回主机名。

▍os.loadavg()


以数组形式返回操作系统计算的平均负载数据。 此信息仅在Linux和macOS上有意义。 它看起来可能像这样:

 [ 3.68798828125, 4.00244140625, 11.1181640625 ] 

▍os.networkInterfaces()


返回有关系统上可用网络接口的信息。 例如:

 { lo0:  [ { address: '127.0.0.1',      netmask: '255.0.0.0',      family: 'IPv4',      mac: 'fe:82:00:00:00:00',      internal: true },    { address: '::1',      netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',      family: 'IPv6',      mac: 'fe:82:00:00:00:00',      scopeid: 0,      internal: true },    { address: 'fe80::1',      netmask: 'ffff:ffff:ffff:ffff::',      family: 'IPv6',      mac: 'fe:82:00:00:00:00',      scopeid: 1,      internal: true } ], en1:  [ { address: 'fe82::9b:8282:d7e6:496e',      netmask: 'ffff:ffff:ffff:ffff::',      family: 'IPv6',      mac: '06:00:00:02:0e:00',      scopeid: 5,      internal: false },    { address: '192.168.1.38',      netmask: '255.255.255.0',      family: 'IPv4',      mac: '06:00:00:02:0e:00',      internal: false } ], utun0:  [ { address: 'fe80::2513:72bc:f405:61d0',      netmask: 'ffff:ffff:ffff:ffff::',      family: 'IPv6',      mac: 'fe:80:00:20:00:00',      scopeid: 8,      internal: false } ] } 

▍os.platform()


返回有关Node.js编译平台的信息。 以下是一些可能的返回值:

  • 达尔文
  • freebsd
  • linux
  • 的openbsd
  • win32的

▍os.release()


返回一个字符串,该字符串标识操作系统的发行版号。

▍os.tmpdir()


返回系统中指定的用于存储临时文件的目录的路径。

▍os.totalmem()


返回以字节为单位的系统内存总量。

▍os.type()


返回标识操作系统的信息。 例如:

  • Linux -Linux。
  • Darwin -macOS。
  • Windows_NT -Windows。

▍os.uptime()


返回自上次重新启动以来的系统正常运行时间(以秒为单位)。

Node.js事件模块


events模块为我们提供了EventEmitter类,该类旨在与Node.js平台上的事件一起使用。 我们已经在本系列文章的第七篇中讨论了这个模块。 这是文档。 在这里,我们看一下该模块的API。 回想一下,要在代码中使用它,您需要将其连接起来,这与标准模块通常是一样的。 之后,您需要创建一个新的EventEmitter对象。 看起来像这样:

 const EventEmitter = require('events') const door = new EventEmitter() 

EventEmitter类的对象使用标准机制,尤其是以下事件:

  • newListener添加事件处理程序时将newListener此事件。
  • removeListener删除处理程序时调用。

考虑一下EventEmitter类的对象的最有用的方法(在方法名称中,相似的对象表示为EventEmitter )。

itteremitter.addListener()


emitter.on()方法的别名。

▍emitter.emit()


生成一个事件。 以注册它们的顺序同步调用所有事件处理程序。

▍emitter.eventNames()


返回包含已注册事件的数组。

▍emitter.getMaxListeners()


返回可以添加到EventEmitter类的对象的最大处理程序数。 默认值为10。如有必要,可以使用setMaxListeners()方法增加或减少此参数。

▍emitter.listenerCount()


返回事件处理程序的数量,事件处理程序的名称作为参数传递给此方法:

 door.listenerCount('open') 

▍emitter.listeners()


返回相应事件的事件处理程序数组,其名称传递给此方法:

 door.listeners('open') 

▍emitter.off()


节点10中引入的emitter.removeListener()方法的别名。

▍emitter.on()


注册在生成事件时调用的回调。 使用方法如下:

 door.on('open', () => { console.log('Door was opened') }) 

▍emitter.once()


它注册仅被调用一次的回调-在首次注册该回调的事件发生时。 例如:

 const EventEmitter = require('events') const ee = new EventEmitter() ee.once('my-event', () => { //         }) 

▍emitter.prependListener()


使用on()addListener()方法注册处理程序时,此处理程序将添加到处理程序队列的末尾,并在最后一次调用以处理相应的事件。 使用prependListener()方法时,将处理程序添加到队列的最前面,这将导致首先调用该处理程序以处理事件。

▍emitter.prependOnceListener()


此方法类似于上一个方法。 即,当使用once()方法注册了打算用于单个调用的处理程序时,它实际上是处理程序队列中的最后一个,也是要调用的最后一个。 prependOnceListener()方法允许您将这样的处理程序添加到队列的前面。

▍emitter.removeAllListeners()


此方法删除在相应对象中注册的给定事件的所有处理程序。 他们这样使用它:

 door.removeAllListeners('open') 

▍emitter.removeListener()


删除要传递给此方法的指定处理程序。 为了保存处理程序以供后续删除,可以将相应的回调分配给变量。 看起来像这样:

 const doSomething = () => {} door.on('open', doSomething) door.removeListener('open', doSomething) 

▍emitter.setMaxListeners()


此方法允许您指定可以添加到EventEmitter类的实例中的单个事件的最大处理程序数。 如前所述,默认情况下,您最多可以为特定事件添加10个处理程序。 该值可以更改。 使用此方法,如下所示:

 door.setMaxListeners(50) 

Node.js http模块


在本系列材料的第八部分中,我们已经讨论了标准的Node.js http模块。 他负责设计用于创建HTTP服务器的开发人员机制。 它是用于解决Node.js中通过网络进行数据交换的问题的主要模块。 您可以通过以下代码将其连接:

 const http = require('http') 

它由属性,方法和类组成。 让我们谈谈他们。

▍物业


http.METHODS


此属性列出了所有受支持的HTTP方法:

 > require('http').METHODS [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE' ] 

http.STATUS_CODES


它包含HTTP状态代码及其描述:

 > require('http').STATUS_CODES { '100': 'Continue', '101': 'Switching Protocols', '102': 'Processing', '200': 'OK', '201': 'Created', '202': 'Accepted', '203': 'Non-Authoritative Information', '204': 'No Content', '205': 'Reset Content', '206': 'Partial Content', '207': 'Multi-Status', '208': 'Already Reported', '226': 'IM Used', '300': 'Multiple Choices', '301': 'Moved Permanently', '302': 'Found', '303': 'See Other', '304': 'Not Modified', '305': 'Use Proxy', '307': 'Temporary Redirect', '308': 'Permanent Redirect', '400': 'Bad Request', '401': 'Unauthorized', '402': 'Payment Required', '403': 'Forbidden', '404': 'Not Found', '405': 'Method Not Allowed', '406': 'Not Acceptable', '407': 'Proxy Authentication Required', '408': 'Request Timeout', '409': 'Conflict', '410': 'Gone', '411': 'Length Required', '412': 'Precondition Failed', '413': 'Payload Too Large', '414': 'URI Too Long', '415': 'Unsupported Media Type', '416': 'Range Not Satisfiable', '417': 'Expectation Failed', '418': 'I\'ma teapot', '421': 'Misdirected Request', '422': 'Unprocessable Entity', '423': 'Locked', '424': 'Failed Dependency', '425': 'Unordered Collection', '426': 'Upgrade Required', '428': 'Precondition Required', '429': 'Too Many Requests', '431': 'Request Header Fields Too Large', '451': 'Unavailable For Legal Reasons', '500': 'Internal Server Error', '501': 'Not Implemented', '502': 'Bad Gateway', '503': 'Service Unavailable', '504': 'Gateway Timeout', '505': 'HTTP Version Not Supported', '506': 'Variant Also Negotiates', '507': 'Insufficient Storage', '508': 'Loop Detected', '509': 'Bandwidth Limit Exceeded', '510': 'Not Extended', '511': 'Network Authentication Required' } 

http.globalAgent


此属性指向http.Agent类的全局实例。 它用于管理连接。 它可以被视为Node.js HTTP子系统的关键组件。 我们将在下面讨论有关类http.Agent更多信息。

▍方法


http.createServer()


返回http.Server类的新实例。 使用此方法创建HTTP服务器的方法如下:

 const server = http.createServer((req, res) => { //      }) 

http.request()


允许您通过创建http.ClientRequest类的实例向服务器发出HTTP请求。

http.get()


此方法类似于http.request() ,但会自动将HTTP方法设置为GET并自动调用req.end()形式的命令。

▍班级


HTTP模块提供5个类ClientRequestClientRequestServerServerResponseIncomingMessage 。 考虑他们。

http.Agent


Node.js创建的http.Agent类的全局实例用于管理连接。 它用作所有HTTP请求的默认值,并提供套接字的排队和重用。 此外,它还支持套接字池,以提高Node.js网络子系统的性能。 如有必要,您可以创建自己的http.Agent对象。

http.ClientRequest


http.request()http.get()方法时,将创建http.ClientRequest类的对象,该对象是一个正在运行的请求。 收到对请求的响应后,将引发响应事件,在该事件中传输响应http.IncomingMessage的实例。 查询完成后获得的数据可以通过两种方式处理:

  • 您可以调用response.read()方法。
  • response事件处理程序中,您可以为data事件配置一个侦听器,从而允许您使用流数据。

http。服务器


此类的实例用于使用http.createServer()命令创建服务器。 在拥有服务器对象之后,我们可以使用其方法:

  • listen()方法用于启动服务器,并组织对传入请求的等待和处理。
  • close()方法停止服务器。

http.ServerResponse


该对象由http.Server类创建,并在发生时作为第二个参数传递给request事件。 通常,在代码中为此类对象分配名称res

 const server = http.createServer((req, res) => { //res -   http.ServerResponse }) 

在这样的处理程序中,在服务器响应准备好发送给客户端之后,将调用end()方法,从而完成响应。 每个响应完成后必须调用此方法。

以下是用于HTTP标头的方法:

  • getHeaderNames() -返回已安装标题的名称列表。
  • getHeaders() -返回设置的HTTP标头的副本。
  • setHeader('headername', value) -设置指定标题的值。
  • getHeader('headername') -返回设置的标题。
  • removeHeader('headername') -删除安装的标题。
  • hasHeader('headername') -如果响应已经具有将其名称传递给此方法的标头,则返回true
  • headersSent() -如果标头已经发送到客户端,则返回true

处理头之后,可以通过调用response.writeHead()方法将它们发送到客户端,该方法作为第一个参数,采用状态码。 作为第二和第三参数,可以将与状态代码和标头相对应的消息传递给它。

要将数据发送到客户端,在响应主体中使用write()方法。 它将缓冲的数据发送到HTTP响应流。

如果尚未使用response.writeHead()命令设置头,则将首先发送带有状态代码和请求中指定的消息的头。 您可以通过设置statusCodestatusMessage值来设置它们的值:

 response.statusCode = 500 response.statusMessage = 'Internal Server Error' 

http.IncomingMessage


通过以下机制来创建http.IncomingMessage类的对象:

  • http.Server处理request事件时。
  • http.ClientRequest处理response事件时。

它可以用于处理响应数据。 即:

  • 为了找出响应状态代码和相应的消息,使用了statusCodestatusMessage属性。
  • 您可以headers rawHearders headersrawHearders (有关原始标头的列表)来查看响应headers头。
  • 您可以使用method属性找到请求方法。
  • 若要查找正在使用哪个版本的HTTP,请使用httpVersion属性。
  • 要获取URL,需要使用url属性。
  • socket属性允许您获取与连接关联的net.Socket对象。

由于http.IncomingMessage对象实现了Readable Stream接口,因此响应数据以流的http.IncomingMessage显示。

在Node.js中使用流


线程是Node.js应用程序中使用的基本概念之一。 流是允许您读取和写入文件,组织系统之间的网络交互以及总体上有效实施数据交换操作的工具。

线程的概念并非Node.js独有。 它们出现在几十年前的Unix系列操作系统上。 特别是,程序可以彼此交互,使用管道(使用管道字符- | )传输数据流。

如果您想像不使用流读取文件,那么在执行相应命令期间,文件的内容将被完全读取到内存中,然后您就可以使用该内容。

由于使用了流机制,因此可以分批读取和处理文件,从而无需在内存中存储大量数据。

Node.js 模块是构建所有支持流的API的基础。

▍关于使用流的优势


与其他数据处理方法相比,流具有以下优点:

  • 有效利用内存。 使用流并不意味着在可以对它们进行处理之前,将大量数据预先存储在内存中。
  • 节省时间。 从流中接收到的数据的处理速度要比必须等待它们完全加载才能开始处理它们的处理速度快得多。

streams使用流的示例


一个使用流的传统示例演示了如何从磁盘读取文件。

首先,考虑不使用线程的代码。 标准的Node.js fs模块允许您读取文件,然后可以响应HTTP服务器收到的请求而通过HTTP传输文件:

 const http = require('http') const fs = require('fs') const server = http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', (err, data) => {   res.end(data) }) }) server.listen(3000) 

此处使用的readFile()方法使您可以读取整个文件。 读取完成后,它将调用相应的回调。

在回调中调用的res.end(data)方法将文件的内容发送到客户端。

如果文件很大,则此操作将花费大量时间。 这是使用流重写的相同示例:

 const http = require('http') const fs = require('fs') const server = http.createServer((req, res) => { const stream = fs.createReadStream(__dirname + '/data.txt') stream.pipe(res) }) server.listen(3000) 

我们无需等待完全读取文件的那一刻,而是在准备好发送数据的第一部分后立即开始将其数据传输到客户端。

▍管道()方法


在前面的示例中,我们使用了stream.pipe(res)形式的构造,其中调用了pipe()文件流方法。 此方法从其源获取数据并将其发送到目的地。

需要一个代表数据源的流。 在这种情况下,这是发送到HTTP响应的文件流。

pipe()方法的返回值是目标流。 这非常方便,因为它允许您将几个调用链接到pipe()方法:

 src.pipe(dest1).pipe(dest2) 

这等效于这样的设计:

 src.pipe(dest1) dest1.pipe(dest2) 

▍使用流的API Node.js


流是一种有用的机制;因此,Node.js内核的许多模块提供了使用流的标准功能。 我们列出其中一些:

  • process.stdin返回连接到stdin的线程。
  • process.stdout返回连接到stdout的线程。
  • process.stderr返回连接到stderr的线程。
  • fs.createReadStream() -创建用于处理文件的可读流。
  • fs.createWriteStream() -创建用于处理文件的可写流。
  • net.connect() -启动基于流的连接。
  • http.request() -返回提供对正在写入的流的访问的http.ClientRequest类的实例。
  • zlib.createGzip() -使用gzip算法压缩数据并将其发送到流。
  • zlib.createGunzip() -解压缩gzip流。
  • zlib.createDeflate() -使用deflate算法压缩数据并将其发送到流。
  • zlib.createInflate() -解压缩deflate流。

streams各种流


流有四种类型:

  • 可读流是可以从中读取数据的流。 您无法将数据写入此类流。 当数据到达这样的流中时,将对其进行缓冲,直到数据使用者开始读取它为止。
  • 写入流( Writable )是可以在其中发送数据的流。 您无法从中读取数据。
  • 双工流( Duplex )-在此流中,您可以发送数据并从中读取数据。 本质上,这是用于读取的流和用于写入的流的组合。
  • 转换流( Transform )-这样的流类似于双工流,不同之处在于这些流的输入将转换可以从中读取的内容。

▍创建读取流


, stream :

 const Stream = require('stream') const readableStream = new Stream.Readable() 

, :

 readableStream.push('hi!') readableStream.push('ho!') 


Writable _write() . :

 const Stream = require('stream') const writableStream = new Stream.Writable() 

_write() :

 writableStream._write = (chunk, encoding, next) => {   console.log(chunk.toString())   next() } 

, :

 process.stdin.pipe(writableStream) 


, , :

 const Stream = require('stream') const readableStream = new Stream.Readable() const writableStream = new Stream.Writable() writableStream._write = (chunk, encoding, next) => {   console.log(chunk.toString())   next() } readableStream.pipe(writableStream) readableStream.push('hi!') readableStream.push('ho!') readableStream.push(null) 

readableStream.push(null) .

, readable :

 readableStream.on('readable', () => { console.log(readableStream.read()) }) 


write() :

 writableStream.write('hey!\n') 

▍ ,


, , end() :

 writableStream.end() 

. , , .

MySQL Node.js


MySQL . Node.js , MySQL-, — , .

mysqljs/mysql . , , 12000 GitHub. , MySQL-.


:

 npm install mysql 


:

 const mysql = require('mysql') 

:

 const options = { user: 'the_mysql_user_name', password: 'the_mysql_user_password', database: 'the_mysql_database_name' } const connection = mysql.createConnection(options) 

:

 connection.connect(err => { if (err) {   console.error('An error occurred while connecting to the DB')   throw err } } 


options :

 const options = { user: 'the_mysql_user_name', password: 'the_mysql_user_password', database: 'the_mysql_database_name' } 

. — :

  • host — , MySQL-, — localhost .
  • port — , — 3306 .
  • socketPath — Unix .
  • debug — , .
  • trace — , .
  • ssl — SSL- .

▍ SELECT


SQL- . query , . — , . . :

 connection.query('SELECT * FROM todos', (error, todos, fields) => { if (error) {   console.error('An error occurred while executing the query')   throw error } console.log(todos) }) 

, :

 const id = 223 connection.query('SELECT * FROM todos WHERE id = ?', [id], (error, todos, fields) => { if (error) {   console.error('An error occurred while executing the query')   throw error } console.log(todos) }) 

, , :

 const id = 223 const author = 'Flavio' connection.query('SELECT * FROM todos WHERE id = ? AND author = ?', [id, author], (error, todos, fields) => { if (error) {   console.error('An error occurred while executing the query')   throw error } console.log(todos) }) 

▍ INSERT


INSERT . , :

 const todo = { thing: 'Buy the milk' author: 'Flavio' } connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => { if (error) {   console.error('An error occurred while executing the query')   throw error } }) 

, , auto_increment , results.insertId :

 const todo = { thing: 'Buy the milk' author: 'Flavio' } connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => { if (error) {   console.error('An error occurred while executing the query')   throw error }} const id = results.resultId console.log(id) ) 


end() :

 connection.end() 

.

-


Node.js -.

Node.js . , -, NODE_ENV :

 NODE_ENV=production 

. Linux, , :

 export NODE_ENV=production 

, , .bash_profile ( Bash), .

, :

 NODE_ENV=production node app.js 

Node.js. NODE_ENV production :

  • .
  • .

, Pug — , Express, , NODE_ENV production . Express, , . - . .

Express . , , NODE_ENV :

 app.configure('development', () => { //... }) app.configure('production', () => { //... }) app.configure('production', 'staging', () => { //... }) 

, :

 app.configure('development', () => { app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }) app.configure('production', () => { app.use(express.errorHandler()) }) 


, , Node.js , . , , , Node.js, - , Node.js.

亲爱的读者们! , Node.js, , .

Source: https://habr.com/ru/post/zh-CN425667/


All Articles