Combinación de conocimientos de Node.js (1) - conceptos básicos

El siguiente contenido proviene del registro de estudio del libro "From Front End to Full Stack"~

Lo usé cuando estaba estudiando V16.20.0, 18+y todavía hay algunas diferencias gramaticales después de eso~

¿Qué es Node.js?

Node.jsEs el entorno de tiempo de ejecución que se ejecuta en el sistema operativo JavaScript , que es diferente del entorno de tiempo de ejecución del navegador:

  • No tiene lo que proporciona el navegador DOM API, como Window objeto, Location objeto, Document objeto, objeto, objeto HTMLElement , Cookie etc.;
  • Proporciona objetos específicos API, como objetos globales , objetos que global también proporcionan información de proceso actual , módulos para manipular archivos y módulos para crear servicios .Process fs Web http

Módulos incorporados comunes

A través de estos módulos incorporados, puede ejecutar instrucciones del sistema operativo, leer y escribir archivos, establecer conexiones de red, llamar a otros servicios en el sistema operativo, etc.:

  • File SystemMódulo: Este es el módulo de directorio y archivo del sistema operativo, que proporciona lectura, escritura, creación, eliminación, configuración de permisos, etc. de archivos y directorios.
  • Net Módulo: proporciona sockets de red socketpara crear TCP conexiones, TCP que se pueden usar para acceder a bases de datos en segundo plano y otros servicios persistentes;
  • HTTP Módulo: Brinda HTTP la capacidad de crear conexiones, se puede usar para crear Web servicios y también es Node.jsel módulo central más comúnmente utilizado en el front-end;
  • URL URL Módulo: un módulo auxiliar utilizado para procesar la información solicitada por el cliente , que puede analizar URL cadenas;
  • Path Módulo: un módulo auxiliar utilizado para procesar la información de la ruta del archivo, que puede analizar la cadena de la ruta del archivo;
  • Process Módulo: utilizado para obtener información del proceso;
  • Buffer Módulo: utilizado para procesar datos binarios;
  • Console Módulo: el módulo de la consola, que es el mismo que el Consolemódulo del navegador, se utiliza para enviar información a la consola;
  • Crypto Módulo de cifrado y descifrado: utilizado para procesar servicios que requieren autorización del usuario;
  • Events Módulo: utilizado para monitorear y enviar eventos de usuario.
// show_builtins.js
const {
    
    builtinModules} = require('module');
console.log(builtinModules);

# 查看所有内置模块明的信息
node show_builtins.js

Gestión modular

La modularización no es extraña, las clasificaciones modulares comunes incluyen ES Module, CommonJS, UMDetc. En 13.20.0+, Node.jsapoyo ES Moduley CommonJSredacción. Revisa la sintaxis:

ES Module

ES Module

Dado que Node.js actualmente usa la especificación CommonJS para definir archivos JS de manera predeterminada, nuestro tipo de archivo es: .mjs.

// module.mjs
export const say = (text) => {
    
    
  console.log('它说', text);
}

// index.mjs
import {
    
     say } from './module.mjs'

const argv = process.argv;
say(argv[2] || 'Hello World');

# 它说 Hello World
node index.mjs

# 它说 Hi,Armouy
node index.mjs 'Hi,Armouy'

Si desea utilizar un archivo ES Modulede definición .js, modifique package.json:

"type": "module",

CommonJS

// module.js
const say = (text) => {
    
    
  console.log('它说', text);
}

module.exports = say;

const say = require('./module')

const argv = process.argv;
say(argv[2] || 'Hello World');

Es posible que haya visto ejemplos del uso exportsde módulos exportados anteriormente, que no se pueden mezclar y se sobrescribirán. Pertenece al método de escritura temprana, y se recomienda ahora .APImodule.exportsmodule.exportsexportsmodule.exports

Aunque ES Modulees compatible CommonJS, pero me da miedo la confusión, hagamos como si no lo supiera, una es que no creo que esté lo suficientemente estandarizado, y la otra es que no sirve de nada recordar esto.

ES Moduley CommonJSla diferencia

  • Configuración de alias:
// ES Module
export {
    
    
  say as sayHello
}

// CommonJS
module.exports = {
    
    
  say: sayHello
}
  • ¿Es posible omitir .jsla extensión:
// ES Module 不可以
import {
    
     say } from './module.mjs'
import {
    
     say } from './module.js'


// CommonJS 可以
const say = require('./module')

  • ES Modulessolo se puede escribir en la capa más externa y no se puede colocar en el alcance de nivel de bloque o alcance de función import:export
// ES Module 以下写法会报错
if(condition) {
    
    
  import {
    
    a} from './foo';
} else {
    
    
  import {
    
    a} from './bar';
}

// CommonJS 以下写法是正确的
let api;
if(condition) {
    
    
  api = require('./foo');
} else {
    
    
  api = require('./bar');
}

  • CommonJS requireEl empalme dinámico es compatible con , ES Moduleslo que no permite:
const libPath = ENV.supportES6 ? './es6/' : './';
const myLib = require(`${
      
      libPath}mylib.js`);
  • ES Modules importAdmite carga dinámica:
(async function() {
    
    
  const {
    
    ziyue} = await import('./ziyue.mjs');
  
  const argv = process.argv;
  console.log(ziyue(argv[2] || '巧言令色,鮮矣仁!'));
}());

En términos generales, cuando escribimos Node.jsmódulos, usamos métodos más estáticos para importar módulos. Pero los módulos de carga dinámica son más útiles en algunas bibliotecas complejas, especialmente en el desarrollo multiplataforma, es posible que necesitemos cargar diferentes módulos para diferentes entornos de plataforma, y ​​la carga dinámica es necesaria en este momento.

MNP

Node.js Proporciona una herramienta de gestión de paquetes que nos permite publicar uno o varios módulos en forma de paquetes a almacenes compartidos en la red. No daré más detalles sobre el contenido de esta parte, pero principalmente recordaré npm runel principio ~

Usualmente configuramos comandos en , y luego los usamos package.jsonpara ejecutar. El éxito se debe a que al instalar el módulo, no solo instale el módulo en el directorio, sino que también cree un subdirectorio .bin debajo del directorio, instale el script de línea de comando en el paquete del módulo en el directorio y configure la variable de entorno PATH del sistema para incluir el directorio durante la ejecución, de modo que el script se pueda ejecutar normalmente ~scriptsnpm run xxxNPM node_modulesnode_modules.binNPM Scriptnode_modules/.bin

npm run eslint
# 相当于
node ./node_modules/.bin/eslint ziyue.js

Aprendiendo de los módulos incorporados

Aquí aprendemos principalmente a través de un proyecto generador de artículos ~

mkdir node-demo
cd node-demo
npm init -y

Modificación package.json:

type": "module",

nuevo corpus/data.json:

{
    
    
  "title": [
    "一天掉多少根头发",
    "中午吃什么",
    "学生会退会",
    "好好学习",
    "生活的意义",
    "科学和人文谁更有意义",
    "熬夜一时爽"
  ],
  "famous":[
    "爱迪生{
    
    {said}},天才是百分之一的勤奋加百分之九十九的汗水。{
    
    {conclude}}",
    "查尔斯·史{
    
    {said}},一个人几乎可以在任何他怀有无限热忱的事情上成功。{
    
    {conclude}}",
    "培根说过,深窥自己的心,而后发觉一切的奇迹在你自己。{
    
    {conclude}}",
    "歌德曾经{
    
    {said}},流水在碰到底处时才会释放活力。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},那脑袋里的智慧,就像打火石里的火花一样,不去打它是不肯出来的。{
    
    {conclude}}",
    "戴尔·卡耐基{
    
    {said}},多数人都拥有自己不了解的能力和机会,都有可能做到未曾梦想的事情。{
    
    {conclude}}",
    "白哲特{
    
    {said}},坚强的信念能赢得强者的心,并使他们变得更坚强。{
    
    {conclude}}",
    "伏尔泰{
    
    {said}},不经巨大的困难,不会有伟大的事业。{
    
    {conclude}}",
    "富勒曾经{
    
    {said}},苦难磨炼一些人,也毁灭另一些人。{
    
    {conclude}}",
    "文森特·皮尔{
    
    {said}},改变你的想法,你就改变了自己的世界。{
    
    {conclude}}",
    "拿破仑·希尔{
    
    {said}},不要等待,时机永远不会恰到好处。{
    
    {conclude}}",
    "塞涅卡{
    
    {said}},生命如同寓言,其价值不在与长短,而在与内容。{
    
    {conclude}}",
    "奥普拉·温弗瑞{
    
    {said}},你相信什么,你就成为什么样的人。{
    
    {conclude}}",
    "吕凯特{
    
    {said}},生命不可能有两次,但许多人连一次也不善于度过。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},人的一生是短的,但如果卑劣地过这一生,就太长了。{
    
    {conclude}}",
    "笛卡儿{
    
    {said}},我的努力求学没有得到别的好处,只不过是愈来愈发觉自己的无知。{
    
    {conclude}}",
    "左拉{
    
    {said}},生活的道路一旦选定,就要勇敢地走到底,决不回头。{
    
    {conclude}}",
    "米歇潘{
    
    {said}},生命是一条艰险的峡谷,只有勇敢的人才能通过。{
    
    {conclude}}",
    "吉姆·罗恩{
    
    {said}},要么你主宰生活,要么你被生活主宰。{
    
    {conclude}}",
    "日本谚语{
    
    {said}},不幸可能成为通向幸福的桥梁。{
    
    {conclude}}",
    "海贝尔{
    
    {said}},人生就是学校。在那里,与其说好的教师是幸福,不如说好的教师是不幸。{
    
    {conclude}}",
    "杰纳勒尔·乔治·S·巴顿{
    
    {said}},接受挑战,就可以享受胜利的喜悦。{
    
    {conclude}}",
    "德谟克利特{
    
    {said}},节制使快乐增加并使享受加强。{
    
    {conclude}}",
    "裴斯泰洛齐{
    
    {said}},今天应做的事没有做,明天再早也是耽误了。{
    
    {conclude}}",
    "歌德{
    
    {said}},决定一个人的一生,以及整个命运的,只是一瞬之间。{
    
    {conclude}}",
    "卡耐基{
    
    {said}},一个不注意小事情的人,永远不会成就大事业。{
    
    {conclude}}",
    "卢梭{
    
    {said}},浪费时间是一桩大罪过。{
    
    {conclude}}",
    "康德{
    
    {said}},既然我已经踏上这条道路,那么,任何东西都不应妨碍我沿着这条路走下去。{
    
    {conclude}}",
    "克劳斯·莫瑟爵士{
    
    {said}},教育需要花费钱,而无知也是一样。{
    
    {conclude}}",
    "伏尔泰{
    
    {said}},坚持意志伟大的事业需要始终不渝的精神。{
    
    {conclude}}",
    "亚伯拉罕·林肯{
    
    {said}},你活了多少岁不算什么,重要的是你是如何度过这些岁月的。{
    
    {conclude}}",
    "韩非{
    
    {said}},内外相应,言行相称。{
    
    {conclude}}",
    "富兰克林{
    
    {said}},你热爱生命吗?那么别浪费时间,因为时间是组成生命的材料。{
    
    {conclude}}",
    "马尔顿{
    
    {said}},坚强的信心,能使平凡的人做出惊人的事业。{
    
    {conclude}}",
    "笛卡儿{
    
    {said}},读一切好书,就是和许多高尚的人谈话。{
    
    {conclude}}",
    "塞涅卡{
    
    {said}},真正的人生,只有在经过艰难卓绝的斗争之后才能实现。{
    
    {conclude}}",
    "易卜生{
    
    {said}},伟大的事业,需要决心,能力,组织和责任感。{
    
    {conclude}}",
    "歌德{
    
    {said}},没有人事先了解自己到底有多大的力量,直到他试过以后才知道。{
    
    {conclude}}",
    "达尔文{
    
    {said}},敢于浪费哪怕一个钟头时间的人,说明他还不懂得珍惜生命的全部价值。{
    
    {conclude}}",
    "佚名{
    
    {said}},感激每一个新的挑战,因为它会锻造你的意志和品格。{
    
    {conclude}}",
    "奥斯特洛夫斯基{
    
    {said}},共同的事业,共同的斗争,可以使人们产生忍受一切的力量。 {
    
    {conclude}}",
    "苏轼{
    
    {said}},古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。{
    
    {conclude}}",
    "王阳明{
    
    {said}},故立志者,为学之心也;为学者,立志之事也。{
    
    {conclude}}",
    "歌德{
    
    {said}},读一本好书,就如同和一个高尚的人在交谈。{
    
    {conclude}}",
    "乌申斯基{
    
    {said}},学习是劳动,是充满思想的劳动。{
    
    {conclude}}",
    "别林斯基{
    
    {said}},好的书籍是最贵重的珍宝。{
    
    {conclude}}",
    "富兰克林{
    
    {said}},读书是易事,思索是难事,但两者缺一,便全无用处。{
    
    {conclude}}",
    "鲁巴金{
    
    {said}},读书是在别人思想的帮助下,建立起自己的思想。{
    
    {conclude}}",
    "培根{
    
    {said}},合理安排时间,就等于节约时间。{
    
    {conclude}}",
    "屠格涅夫{
    
    {said}},你想成为幸福的人吗?但愿你首先学会吃得起苦。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},抛弃时间的人,时间也抛弃他。{
    
    {conclude}}",
    "叔本华{
    
    {said}},普通人只想到如何度过时间,有才能的人设法利用时间。{
    
    {conclude}}",
    "博{
    
    {said}},一次失败,只是证明我们成功的决心还够坚强。 维{
    
    {conclude}}",
    "拉罗什夫科{
    
    {said}},取得成就时坚持不懈,要比遭到失败时顽强不屈更重要。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},人的一生是短的,但如果卑劣地过这一生,就太长了。{
    
    {conclude}}",
    "俾斯麦{
    
    {said}},失败是坚忍的最后考验。{
    
    {conclude}}",
    "池田大作{
    
    {said}},不要回避苦恼和困难,挺起身来向它挑战,进而克服它。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},那脑袋里的智慧,就像打火石里的火花一样,不去打它是不肯出来的。{
    
    {conclude}}",
    "希腊{
    
    {said}},最困难的事情就是认识自己。{
    
    {conclude}}",
    "黑塞{
    
    {said}},有勇气承担命运这才是英雄好汉。{
    
    {conclude}}",
    "非洲{
    
    {said}},最灵繁的人也看不见自己的背脊。{
    
    {conclude}}",
    "培根{
    
    {said}},阅读使人充实,会谈使人敏捷,写作使人精确。{
    
    {conclude}}",
    "斯宾诺莎{
    
    {said}},最大的骄傲于最大的自卑都表示心灵的最软弱无力。{
    
    {conclude}}",
    "西班牙{
    
    {said}},自知之明是最难得的知识。{
    
    {conclude}}",
    "塞内加{
    
    {said}},勇气通往天堂,怯懦通往地狱。{
    
    {conclude}}",
    "赫尔普斯{
    
    {said}},有时候读书是一种巧妙地避开思考的方法。{
    
    {conclude}}",
    "笛卡儿{
    
    {said}},阅读一切好书如同和过去最杰出的人谈话。{
    
    {conclude}}",
    "邓拓{
    
    {said}},越是没有本领的就越加自命不凡。{
    
    {conclude}}",
    "爱尔兰{
    
    {said}},越是无能的人,越喜欢挑剔别人的错儿。{
    
    {conclude}}",
    "老子{
    
    {said}},知人者智,自知者明。胜人者有力,自胜者强。{
    
    {conclude}}",
    "歌德{
    
    {said}},意志坚强的人能把世界放在手中像泥块一样任意揉捏。{
    
    {conclude}}",
    "迈克尔·F·斯特利{
    
    {said}},最具挑战性的挑战莫过于提升自我。{
    
    {conclude}}",
    "爱迪生{
    
    {said}},失败也是我需要的,它和成功对我一样有价值。{
    
    {conclude}}",
    "罗素·贝克{
    
    {said}},一个人即使已登上顶峰,也仍要自强不息。{
    
    {conclude}}",
    "马云{
    
    {said}},最大的挑战和突破在于用人,而用人最大的突破在于信任人。{
    
    {conclude}}",
    "雷锋{
    
    {said}},自己活着,就是为了使别人过得更美好。{
    
    {conclude}}",
    "布尔沃{
    
    {said}},要掌握书,莫被书掌握;要为生而读,莫为读而生。{
    
    {conclude}}",
    "培根{
    
    {said}},要知道对好事的称颂过于夸大,也会招来人们的反感轻蔑和嫉妒。{
    
    {conclude}}",
    "莫扎特{
    
    {said}},谁和我一样用功,谁就会和我一样成功。{
    
    {conclude}}",
    "马克思{
    
    {said}},一切节省,归根到底都归结为时间的节省。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},意志命运往往背道而驰,决心到最后会全部推倒。{
    
    {conclude}}",
    "卡莱尔{
    
    {said}},过去一切时代的精华尽在书中。{
    
    {conclude}}",
    "培根{
    
    {said}},深窥自己的心,而后发觉一切的奇迹在你自己。{
    
    {conclude}}",
    "罗曼·罗兰{
    
    {said}},只有把抱怨环境的心情,化为上进的力量,才是成功的保证。{
    
    {conclude}}",
    "孔子{
    
    {said}},知之者不如好之者,好之者不如乐之者。{
    
    {conclude}}",
    "达·芬奇{
    
    {said}},大胆和坚定的决心能够抵得上武器的精良。{
    
    {conclude}}",
    "叔本华{
    
    {said}},意志是一个强壮的盲人,倚靠在明眼的跛子肩上。{
    
    {conclude}}",
    "黑格尔{
    
    {said}},只有永远躺在泥坑里的人,才不会再掉进坑里。{
    
    {conclude}}",
    "普列姆昌德{
    
    {said}},希望的灯一旦熄灭,生活刹那间变成了一片黑暗。{
    
    {conclude}}",
    "维龙{
    
    {said}},要成功不需要什么特别的才能,只要把你能做的小事做得好就行了。{
    
    {conclude}}",
    "郭沫若{
    
    {said}},形成天才的决定因素应该是勤奋。{
    
    {conclude}}",
    "洛克{
    
    {said}},学到很多东西的诀窍,就是一下子不要学很多。{
    
    {conclude}}",
    "西班牙{
    
    {said}},自己的鞋子,自己知道紧在哪里。{
    
    {conclude}}",
    "拉罗什福科{
    
    {said}},我们唯一不会改正的缺点是软弱。{
    
    {conclude}}",
    "亚伯拉罕·林肯{
    
    {said}},我这个人走得很慢,但是我从不后退。{
    
    {conclude}}",
    "美华纳{
    
    {said}},勿问成功的秘诀为何,且尽全力做你应该做的事吧。{
    
    {conclude}}",
    "俾斯麦{
    
    {said}},对于不屈不挠的人来说,没有失败这回事。{
    
    {conclude}}",
    "阿卜·日·法拉兹{
    
    {said}},学问是异常珍贵的东西,从任何源泉吸收都不可耻。{
    
    {conclude}}",
    "白哲特{
    
    {said}},坚强的信念能赢得强者的心,并使他们变得更坚强。 {
    
    {conclude}}",
    "查尔斯·史考伯{
    
    {said}},一个人几乎可以在任何他怀有无限热忱的事情上成功。 {
    
    {conclude}}",
    "贝多芬{
    
    {said}},卓越的人一大优点是:在不利与艰难的遭遇里百折不饶。{
    
    {conclude}}",
    "莎士比亚{
    
    {said}},本来无望的事,大胆尝试,往往能成功。{
    
    {conclude}}",
    "卡耐基{
    
    {said}},我们若已接受最坏的,就再没有什么损失。{
    
    {conclude}}",
    "德国{
    
    {said}},只有在人群中间,才能认识自己。{
    
    {conclude}}",
    "史美尔斯{
    
    {said}},书籍把我们引入最美好的社会,使我们认识各个时代的伟大智者。{
    
    {conclude}}",
    "冯学峰{
    
    {said}},当一个人用工作去迎接光明,光明很快就会来照耀着他。{
    
    {conclude}}",
    "吉格·金克拉{
    
    {said}},如果你能做梦,你就能实现它。{
    
    {conclude}}"
  ],
  "bosh_before": [
    "既然如此,",
    "那么,",
    "我认为,",
    "一般来说,",
    "总结的来说,",
    "无论如何,",
    "经过上述讨论,",
    "这样看来,",
    "从这个角度来看,",
    "现在,解决{
    
    {title}}的问题,是非常非常重要的。 所以,",
    "每个人都不得不面对这些问题。在面对这种问题时,",
    "我们不得不面对一个非常尴尬的事实,那就是,",
    "而这些并不是完全重要,更加重要的问题是,",
    "我们不妨可以这样来想: "
  ],
  "bosh":[
    "{
    
    {title}}的发生,到底需要如何做到,不{
    
    {title}}的发生,又会如何产生。 ",
    "{
    
    {title}},到底应该如何实现。 ",
    "带着这些问题,我们来审视一下{
    
    {title}}。 ",
    "所谓{
    
    {title}},关键是{
    
    {title}}需要如何写。 ",
    "我们一般认为,抓住了问题的关键,其他一切则会迎刃而解。",
    "问题的关键究竟为何? ",
    "{
    
    {title}}因何而发生?",
    "一般来讲,我们都必须务必慎重的考虑考虑。 ",
    "要想清楚,{
    
    {title}},到底是一种怎么样的存在。 ",
    "了解清楚{
    
    {title}}到底是一种怎么样的存在,是解决一切问题的关键。",
    "就我个人来说,{
    
    {title}}对我的意义,不能不说非常重大。 ",
    "本人也是经过了深思熟虑,在每个日日夜夜思考这个问题。 ",
    "{
    
    {title}},发生了会如何,不发生又会如何。 ",
    "在这种困难的抉择下,本人思来想去,寝食难安。",
    "生活中,若{
    
    {title}}出现了,我们就不得不考虑它出现了的事实。 ",
    "这种事实对本人来说意义重大,相信对这个世界也是有一定意义的。",
    "我们都知道,只要有意义,那么就必须慎重考虑。",
    "这是不可避免的。 ",
    "可是,即使是这样,{
    
    {title}}的出现仍然代表了一定的意义。 ",
    "{
    
    {title}}似乎是一种巧合,但如果我们从一个更大的角度看待问题,这似乎是一种不可避免的事实。 ",
    "在这种不可避免的冲突下,我们必须解决这个问题。 ",
    "对我个人而言,{
    
    {title}}不仅仅是一个重大的事件,还可能会改变我的人生。 "
  ],
  "conclude":[
    "这不禁令我深思。 ",
    "带着这句话,我们还要更加慎重的审视这个问题: ",
    "这启发了我。",
    "我希望诸位也能好好地体会这句话。 ",
    "这句话语虽然很短,但令我浮想联翩。",
    "这句话看似简单,但其中的阴郁不禁让人深思。",
    "这句话把我们带到了一个新的维度去思考这个问题:",
    "这似乎解答了我的疑惑。"
  ],
  "said":[
    "曾经说过",
    "在不经意间这样说过",
    "说过一句著名的话",
    "曾经提到过",
    "说过一句富有哲理的话"
  ]
}

módulo fs

fsEl módulo es principalmente para operaciones de lectura y escritura en archivos. Primero, para realizar la lectura de archivos, hay principalmente dos involucrados aquí API:

  • readFile leer el contenido del archivo de forma asíncrona
  • readFileSync Leer el contenido del archivo sincrónicamente

En general, lo usaré readFileSync. La sincronización es mejor para mantener el código. Aquí leemos los data.jsonarchivos anteriores. Cabe señalar que, dado que la salida readFile o readFileSync la salida son todos objetos de búfer, deben formatearse al generarlos ~

// index.js
import {
    
     readFileSync } from 'fs';

const data = readFileSync('./corpus/data.json', {
    
     encoding: 'utf-8' });
console.log(data);

La ruta del archivo aquí usa una ruta relativa, que no es muy común. Cuando lo ejecuta fuera del proyecto, node node-demo/index.jsse informará un error ENOENT: no such file or directory, open './corpus/data.json'porque se ./corpus/data.jsonentenderá como un archivo debajo del archivo que actualmente ejecuta el comando corpus/data.json~

Entonces, aquí debe usar el módulo urly path~ para convertir la ruta relativa en una ruta absoluta:

import {
    
     readFileSync } from 'fs';
import {
    
     fileURLToPath } from 'url';
import {
    
     dirname, resolve } from 'path';

// 获得当前脚本文件的 URL 地址, 类似:file:///.../node-demo/index.js
const url = import.meta.url;
/**
 * 当前脚本文件的 url 地址转化成文件路径
 * 通过 resolve 将相对路径转变成 data.json 文件的绝对路径
 * dirname方法可以获得当前 JS 文件的目录
 * resolve方法可以将 JS 文件目录和相对路径拼在一起
 */
const path = resolve(dirname(fileURLToPath(url)), './corpus/data.json');
const data = readFileSync(path, {
    
     encoding: 'utf-8' });
const corpus = JSON.parse(data);
console.log(corpus );

Lo anterior es ES Modulela forma de escribir. Con respecto a la ruta de conversión, CommonJSresolvámoslo en una oración:

const path = resolve(__dirname, './corpus/data.json');

Omita el capítulo sobre la generación de módulos aleatorios y agregue el código directamente:

// lib/random.js
// 返回一定范围内的整数,用来控制随机生成的文章和段落的长度范围
export function randomInt(min = 0, max = 100) {
    
    
  const p = Math.random();
  return Math.floor(min * (1 - p) + max * p);
}

// 函数能够从语料库的数组中随机地选择元素,并返回
export function createRandomPicker(arr) {
    
    
  arr = [...arr]; // copy 数组,以免修改原始数据
  function randomPick() {
    
    
    const len = arr.length - 1;
    const index = randomInt(0, len);
    const picked = arr[index];
    [arr[index], arr[len]] = [arr[len], arr[index]];
    return picked;
  }
  randomPick(); // 抛弃第一次选择结果
  return randomPick;
}

// lib/generator.js
import {
    
    randomInt, createRandomPicker} from './random.js';

function sentence(pick, replacer) {
    
    
  let ret = pick();
  for(const key in replacer) {
    
    
    ret = ret.replace(new RegExp(`{
     
     {
     
     ${
      
      key}}}`, 'g'),
      typeof replacer[key] === 'function' ? replacer[key]() : replacer[key]);
  }
  return ret;
}

export function generate(title, {
    
    
  corpus,
  min = 6000, // 文章最少字数
  max = 10000, // 文章最多字数
} = {
    
    }) {
    
    
  const articleLength = randomInt(min, max);
  const {
    
    famous, bosh_before, bosh, said, conclude} = corpus;
  const [pickFamous, pickBoshBefore, pickBosh, pickSaid, pickConclude]
    = [famous, bosh_before, bosh, said, conclude].map(createRandomPicker);

  const article = [];
  let totalLength = 0;

  while(totalLength < articleLength) {
    
    
    let section = '';
    const sectionLength = randomInt(200, 500); // 每段200到500字
    while(section.length < sectionLength || !/[。?]$/.test(section)) {
    
    
      const n = randomInt(0, 100);
      if(n < 20) {
    
    
        section += sentence(pickFamous, {
    
    said: pickSaid, conclude: pickConclude});
      } else if(n < 50) {
    
    
        section += sentence(pickBoshBefore, {
    
    title}) + sentence(pickBosh, {
    
    title});
      } else {
    
    
        section += sentence(pickBosh, {
    
    title});
      }
    }
    totalLength += section.length;
    article.push(section);
  }

  return article;
}

El código anterior implementa principalmente cómo obtener fragmentos aleatorios data.jsonde él , y luego mostraremos los artículos generados:

// index.js
import {
    
     readFileSync } from 'fs';
import {
    
     fileURLToPath } from 'url';
import {
    
     dirname, resolve } from 'path';

import {
    
     generate } from './lib/generator.js';
import {
    
     createRandomPicker } from './lib/random.js';

const __dirname = dirname(fileURLToPath(import.meta.url));

// 获取data.json
function loadCorpus(src) {
    
    
  const path = resolve(__dirname, src);
  const data = readFileSync(path, {
    
    encoding: 'utf-8'});
  return JSON.parse(data);
}

const corpus = loadCorpus('./corpus/data.json');
// 生成随机title
const pickTitle = createRandomPicker(corpus.title);
const title = pickTitle();
// 生成随机文章
const article = generate(title, {
    
    corpus});
console.log(`${
      
      title}\n\n    ${
      
      article.join('\n    ')}`);


Con la ayuda fsde guardar API, guarde el contenido generado en el archivo ~

npm i moment --save
function saveCorpus(title, article) {
  // 设置输出目录的路径
  const outputDir = resolve(__dirname, 'output');
  // 是否存在输出目录,不存在则创建
  if(!existsSync(outputDir)) {
    mkdirSync(outputDir);
  }
  // 创建时间戳
  const time = moment().format('|YYYY-MM-DD|HH:mm:ss');
  // 获取输出的文件路径
  const outputFile = resolve(outputDir, `${title}${time}.txt`);
  // 获得输出内容
  const text = `${title}\n\n    ${article.join('\n    ')}`;
  // 如果文件不存在会自动创建,但是如果文件明有问题,会告诉你找不到该文件,所以起名慎重
  writeFileSync(outputFile, text);

  return outputFile;
}

Extraiga loadCorpusla suma saveCorpusen lib/corpus.js~

// index.js
import {
    
     loadCorpus, saveCorpus } from './lib/corpus.js';
import {
    
     generate } from './lib/generator.js';
import {
    
     createRandomPicker } from './lib/random.js';

const corpus = loadCorpus('corpus/data.json');
const pickTitle = createRandomPicker(corpus.title);
const title = pickTitle();
const article = generate(title, {
    
    corpus});
saveCorpus(title, article);

La ejecución node.jsguardará outputel archivo en el directorio ~

módulo de proceso

Aquí se trata principalmente de realizar la interacción de la línea de comandos con los parámetros.

Como se mencionó anteriormente, podemos leer variables como esta:

const argv = process.argv;
// 执行node node.js的命令,
// 这时候process.argv的值是数组['node', 'node.js']

Ingresamos el título del texto, el número mínimo de palabras y el número máximo de palabras en la línea de comando para optimizar nuestra generación aleatoria de artículos ~

Primero, definamos las variables que se pueden ingresar:

node index.js --min 100 --max 200  --title 文章标题

A continuación, debemos verificar las variables de entrada para evitar encontrar variables indefinidas ~ aquí con la ayuda de command-line-args :

npm install command-line-args --save
import commandLineArgs from 'command-line-args';

// ...

const optionDefinitions = [
  {
    
     name: 'title', alias: 't', type: String },
  {
    
     name: 'min', type: Number},
  {
    
     name: 'max', type: Number},
];
// 从命令行获取输入
const options = commandLineArgs(optionDefinitions);

Aquí puede verificar si los parámetros son legales y luego podemos pasar estos parámetros a la función como variables ~

Para la interacción normal de la línea de comandos, debe haber una —helpvariable para solicitar al usuario que ingrese, lo que se hace aquí con la ayuda de command-line-usage :

npm install command-line-args --save

Encapsule todo lo relacionado con la línea de comandos en lib/cmd.js:

import commandLineArgs from 'command-line-args';
import commandLineUsage from 'command-line-usage';

// 定义help提示
const sections = [
  {
    
    
    header: '狗屁不通文章生成器',
    content: '生成随机的文章段落用于测试',
  },
  {
    
    
    header: 'Options',
    optionList: [
      {
    
    
        name: 'title',
        typeLabel: '{underline string}',
        description: '文章的主题。',
      },
      {
    
    
        name: 'min',
        typeLabel: '{underline number}',
        description: '文章最小字数。',
      },
      {
    
    
        name: 'max',
        typeLabel: '{underline number}',
        description: '文章最大字数。',
      },
    ],
  },
];

const usage = commandLineUsage(sections);

// 定义可以输入的参数
const optionDefinitions = [
  {
    
    name: 'help'},
  {
    
    name: 'title', type: String},
  {
    
    name: 'min', type: Number},
  {
    
    name: 'max', type: Number},
];

const options = commandLineArgs(optionDefinitions);

if('help' in options) {
    
    
  console.log(usage);
  // 输入--help之后记得退出程序
  process.exit();
}

export {
    
     options } ;

// index.js
import {
    
     loadCorpus, saveCorpus } from './lib/corpus.js';
import {
    
     generate } from './lib/generator.js';
import {
    
     createRandomPicker } from './lib/random.js';
import {
    
    options} from './lib/cmd.js';

const corpus = loadCorpus('corpus/data.json');
const title = options.title || createRandomPicker(corpus.title)();
const article = generate(title, {
    
    corpus, ...options});
const output = saveCorpus(title, article);

console.log(`生成成功!文章保存于:${
      
      output}`);


node index.js --help

La interacción mencionada anteriormente no es muy flexible, escribimos los parámetros en node index.jsla parte posterior y luego aprendemos cómo cmdgenerar artículos leyendo los parámetros ingresados ​​​​por el usuario ~ Aquí usamos principalmente process.stdiny readline:

Primero, diseñe una estructura de datos de preguntas:

[
  {
    
    text: '请输入文章主题', value: title},
  {
    
    text: '请输入最小字数', value: 6000},
  {
    
    text: '请输入最大字数', value: 10000},
]

A continuación creamos lib/interact.js:

import readline from 'readline';

function question(rl, {
     
     text, value}){
    
    
  const q = `${
      
      text}(${
      
      value})\n`;
  return new Promise((resolve) => {
    
    
    rl.question(q, (answer) => {
    
    
      resolve(answer || value);
    });
  });
}

export async function interact(questions) {
    
    
  const rl = readline.createInterface({
    
    
    input: process.stdin,
    output: process.stdout
  });

  const answers = [];

  for(let i = 0; i < questions.length; i++) {
    
    
    const q = questions[i];
    // 每次输出一个提问并等待用户输入答案
    const answer = await question(rl, q);
    answers.push(answer);
  }

  rl.close();
  return answers;
}
// index.js
import {
    
     loadCorpus, saveCorpus } from './lib/corpus.js';
import {
    
     generate } from './lib/generator.js';
import {
    
     createRandomPicker } from './lib/random.js';
import {
    
     options } from './lib/cmd.js';
import {
    
     interact } from './lib/interact.js'

const corpus = loadCorpus('corpus/data.json');
let title = options.title || createRandomPicker(corpus.title)();

(async function () {
    
    
  if(Object.keys(options).length <= 0) {
    
    
    const answers = await interact([
      {
    
    text: '请输入文章主题', value: title},
      {
    
    text: '请输入最小字数', value: 6000},
      {
    
    text: '请输入最大字数', value: 10000},
    ]);
    title = answers[0];
    options.min = answers[1];
    options.max = answers[2];
  }

  const article = generate(title, {
    
    corpus, ...options});
  const output = saveCorpus(title, article);

  console.log(`生成成功!文章保存于:${
      
      output}`);
}());


# node index.js
请输入文章主题(科学和人文谁更有意义)
Armouy
请输入最小字数(6000)
100
请输入最大字数(10000)
200
生成成功!文章保存于:D:\...\node-demo\output\Armouy2023-07-03-11-48-58.txt

módulo de red

Utilice principalmente este módulo para implementar un TCPservidor.

import net from 'net';

function responseData(str, status = 200, desc = 'OK') {
    
    
  return `HTTP/1.1 ${
      
      status} ${
      
      desc}
Connection: keep-alive
Date: ${
      
      new Date()}
Content-Length: ${
      
      str.length}
Content-Type: text/html

${
      
      str}`;
}

const server = net.createServer((socket) => {
    
    
  socket.on('data', (data) => {
    
    
    const matched = data.toString('utf-8').match(/^GET ([/\w]+) HTTP/);
    if(matched) {
    
    
      const path = matched[1];
      // 如果路径是/,则返回 200,否则返回 404
      if(path === '/') {
    
     
        socket.write(responseData('<h1>Hello world</h1>'));
      } else {
    
     
        socket.write(responseData('<h1>Not Found</h1>', 404, 'NOT FOUND'));
      }
    }
    console.log(`DATA:\n\n${
      
      data}`);
  });

  socket.on('close', () => {
    
    
    console.log('connection closed, goodbye!\n\n\n');
  });
}).on('error', (err) => {
    
    
  throw err;
});

server.listen({
    
    
  host: '0.0.0.0',
  port: 8080,
}, () => {
    
    
  console.log('opened server on', server.address());
});

Módulo HTTP

Usamos netmódulos para construir TCPservicios antes. Por lo general, es más conveniente para nosotros httpconstruir un servidor directamente con módulos . En comparación con usar servicios para procesar solicitudes, usar servicios para procesar solicitudes es más simple, porque no necesitamos analizar manualmente el mensaje de solicitud y organizar el mensaje de respuesta con plantillas de cadena.httpTCP HTTP http HTTP HTTP HTTP

La implementación simple urldevuelve contenido de página diferente según el contenido diferente:

// http-simple.js
import http from 'http';
import url from 'url';

// req 表示 HTTP 请求对象,res 表示 HTTP 响应对象
const server = http.createServer((req, res) => {
    
    
  const {
    
     pathname } = url.parse(`http://${
      
      req.headers.host}${
      
      req.url}`);
  /**
   * 在返回 HTTP 响应内容时,我们不再需要自己拼接模板字符串和计算Content-length。
   * http 模块会自动完成这个工作并将Content-length写入响应头。
   * 我们还可以直接用res.writeHead来写入其他 HTTP 响应头,
   * 用res.end来写入 HTTP 的 Body 部分。
   */
  if(pathname === '/') {
    
    
    res.writeHead(200, {
    
    'Content-Type': 'text/html'});
    res.end('<h1>Hello world</h1>');
  }else {
    
    
    res.writeHead(404, {
    
    'Content-Type': 'text/html'});
    res.end('<h1>Not Found</h1>');
  }
})

server.on('clientError', (err, socket) => {
    
    
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
})

server.listen(8080, () => {
    
    
  console.log('opened server on', server.address());
});


A continuación, implemente un servidor de recursos estático común y devuelva el archivo correspondiente según la dirección URL:

Primero instale un paquete de dependencia, debemos modificar el tipo de contenido cuando devuelva diferentes tipos de archivos, de lo contrario, el navegador no lo reconocerá correctamente, por lo que debemos usar este paquete:

npm i mime --save

Cree una nueva carpeta www en el proyecto y coloque tres archivos dentro:

- 1.jpg
- index.html
- test.js

Podemos acceder a los recursos correspondientes a través de estas rutas:

- http://localhost:8080/1.jpg
- http://localhost:8080/ 或者 http://localhost:8080/index.html
- http://localhost:8080/test.js

El siguiente paso es escribir el código:

// http-static.js
import http from 'http';
import {
    
     fileURLToPath } from 'url';
import {
    
     dirname, resolve, join, parse } from 'path';
import fs from 'fs';
import mime from 'mime';

const __dirname = dirname(fileURLToPath(import.meta.url));

const server = http.createServer((req, res) => {
    
    
  // 将想要获取的文件路径格式化一下,转成绝对路径
  let filePath = resolve(__dirname, join('www', `${
      
      req.url}`));

  // 判断文件是否存在
  if(fs.existsSync(filePath)) {
    
    
    // 判断是否是文件目录
    const stats = fs.statSync(filePath);
    const isDir = stats.isDirectory();

    if(isDir) {
    
    
      // 如果是目录,则访问的是index.html
      filePath = join(filePath, 'index.html');
    }

    const content = fs.readFileSync(filePath);
    // 获取文件后缀
    const {
    
     ext } = parse(filePath);
    // 根据文件类型返回不同的Content-Type
    res.writeHead(200, {
    
    'Content-Type': mime.getType(ext)}); 
    return res.end(content); 
  }
  res.writeHead(404, {
    
    'Content-Type': 'text/html'});
  res.end('<h1>Not Found</h1>');
});

server.on('clientError', (err, socket) => {
    
    
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});

server.listen(8080, () => {
    
    
  console.log('opened server on', server.address());
});


módulo de flujo

Cuando el front-end lee recursos estáticos, debemos esperar a que se lea todo el contenido del archivo antes de enviarlo. Usando el streammódulo, el archivo se puede leer de forma continua y los datos recibidos se envían continuamente al navegador del cliente, para evitar el consumo de memoria y el bloqueo de archivos cuando el contenido del archivo es demasiado grande I/O.

const server = http.createServer((req, res) => {
    
    
  // 将想要获取的文件路径格式化一下,转成绝对路径
  let filePath = resolve(__dirname, join('www', `${
      
      req.url}`));

  // 判断文件是否存在
  if(fs.existsSync(filePath)) {
    
    
    // 判断是否是文件目录
    const stats = fs.statSync(filePath);
    const isDir = stats.isDirectory();

    if(isDir) {
    
    
      // 如果是目录,则访问的是index.html
      filePath = join(filePath, 'index.html');
    }

    // 获取文件后缀
    const {
    
     ext } = parse(filePath);
    // 根据文件类型返回不同的Content-Type
    res.writeHead(200, {
    
    'Content-Type': mime.getType(ext)}); 
    // 以流的方式读取
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);
  }else {
    
    
    res.writeHead(404, {
    
    'Content-Type': 'text/html'});
    res.end('<h1>Not Found</h1>');
  }
});

(El generador de artículos aleatorios termina aquí, y el siguiente contenido se basa en el avance de los puntos de conocimiento anteriores y no tiene nada que ver con la realización de funciones~)

Resumir

Revisó las diferencias en el funcionamiento Node.jscon los navegadores , resolvió las diferencias en el uso de la modularización y el uso de módulos integrados comunes ~JS

Link de referencia

Del front-end al full-stack


Si comete errores, indíquelos, gracias por leer ~

Supongo que te gusta

Origin blog.csdn.net/qq_34086980/article/details/131524900
Recomendado
Clasificación