重学Node.js及其框架(Express, Koa, egg.js) 之 Nodejs基础(上)

简介: 重学Node.js及其框架(Express, Koa, egg.js) 之 Nodejs基础

总结自 Coderwhy的nodejs课程。


Express总结: juejin.cn/post/701653…


Koa总结:juejin.cn/post/701658…


nodejs官网:nodejs.org/dist/latest…


Nodejs是什么


Node.js是一个基于V8 JavaScript引擎的JavaScript运行时环境。


V8引擎原理


网络异常,图片无法展示
|


Parse模块会将JavaScript代码转换成AST(抽象语法树),这是因为解释器并不直接认识JavaScript代码;


  • 如果函数没有被调用,那么是不会被转换成AST的;


  • Parse的V8官方文档:v8.dev/blog/scanne…Ignition是一个解释器,会将AST转换成ByteCode(字节码)


  • 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算);


  • 如果函数只调用一次,Ignition会执行解释执行ByteCode;


  • Ignition的V8官方文档:v8.dev/blog/igniti…TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码;


  • 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能;


  • 但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码;


  • TurboFan的V8官方文档:v8.dev/blog/turbof…上面是JavaScript代码的执行过程,事实上V8的内存回收也是其强大的另外一个原因,不过这里暂时先不展开讨论:


  • Orinoco模块,负责垃圾回收,将程序中不需要的内存回收;



Node.js架构


  • 我们编写的JavaScript代码会经过V8引擎,再通过Node.js的Bindings,将任务放到Libuv的事件循环中;


  • libuv(Unicorn Velociraptor—独角伶盗龙)是使用C语言编写的库;


  • libuv提供了事件循环、文件系统读写、网络IO、线程池等等内容;


网络异常,图片无法展示
|


Nodejs的全局对象


一些有用的全局对象。


  • __dirname:获取当前文件所在的文件夹的绝对路径


  • __filename:获取当前文件的绝对路径:


  • process对象:


  • cwd(): 获取当前终端运行的文件夹绝对路径。


  • argv:获取在终端执行时传入的参数。


  • env:获取当前程序的环境变量。


Node.js模块化


Node中对CommonJS进行了支持和实现,让我们在开发node的过程中可以方便的进行模块化开发:


  • 在Node中每一个js文件都是一个单独的模块;


  • 这个模块中包括CommonJS规范的核心变量:exports、module.exports、require


  • exportsmodule.exports可以负责对模块中的内容进行导出;


  • require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容; 下面我们将来介绍exports、module.exports、require的使用。


  • exports是一个对象,我们可以在这个对象中添加很多个属性,添加的属性会导出;


  • 我们也可以通过module.exports直接导出一个对象。


  • 我们通过require()函数导入一个文件。并且该文件导出的变量。 下面来详细介绍一个module.exports


  • CommonJS中是没有module.exports的概念的;


  • 但是为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是module;


  • 所以在Node中真正用于导出的其实根本不是exports,而是module.exports;


  • 因为module才是导出的真正实现者;


  • 并且内部将exports赋值给module.exports。 该方式的导入导出有一个特点。


具体请访问:juejin.cn/post/701299…


  • Node中的文件都运行在一个函数中。可以通过打印console.log(arguments.callee + "")来验证。


  • 导入导出是值的引用,如果导出的是一个基本数据类型值,那么导出文件改变该值,然后导入文件该变量的值也不会变。


  • 他是通过require 函数来导入的,只有在执行js代码才会知道模块的依赖关系。


  • 代码是同步执行的。


  • 模块多次引入,只会加载一次。每个module内部会存在一个loaded来确定是否被加载过


  • 代码循环引入的时候,深度优先来加载模块。然后再广度优先。


path模块


只介绍一些常用的API


由于不同操作系统可能使用不同的路径分隔符,所以join方法就非常有用。


  • resolve: 拼接路径。这个会根据传入的第一个路径前面是否有/,../,./来查找本地的完整目录,然后再拼接传入的其他路径。如果第一个传入的路径/开头的,那么将把路径拼接到当前执行文件的绝对路径后面。如果最后一个传入的路径通过/开头,那么我们将直接忽略前面传入的路径参数。


  • join:路径拼接。这个就是传入的是啥拼接的就是啥。傻瓜式拼接。但是也会根据../来拼接上一级


const { resolve, join } = require("path")
    const first = '/zhang';
    const second = "./hao" || '../hao'
    const third = './llm' || '/llm'
    console.log(resolve( first, second, third)) //C:\zhang\hao\llm || C:\hao\llm || C:\llm
    console.log(join(first, second, third)) // \zhang\hao\llm || \hao\llm || \zhang\hao\llm


网络异常,图片无法展示
|


  • dirname:获取文件的父文件夹;


  • basename:获取文件名;


  • extname:获取文件扩展名;


const path = require("path")
    const url = "c:/zh/study/nodejs/index.js";
    console.log(path.dirname(url))// c:/zh/study/nodejs 
    console.log(path.basename(url))// index.js
    console.log(path.extname(url))//.js


fs模块


fs模块大部分API的实现都有三种方法。


  • 方式一:同步操作文件:代码会被阻塞,不会继续执行;


  • 方式二:异步回调函数操作文件:代码不会被阻塞,需要传入回调函数,当获取到结果时,回调函数被执行;


  • 方式三:异步Promise操作文件:代码不会被阻塞,通过 fs.promises 调用方法操作,会返回一个Promise,可以通过then、catch进行处理;


方式一:同步操作文件


// 1.方式一: 同步读取文件
const state = fs.statSync('../foo.txt');
console.log(state);
console.log('后续代码执行');


方式二:异步回调函数操作文件


// 2.方式二: 异步读取
fs.stat("../foo.txt", (err, state) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log(state);
})
console.log("后续代码执行");


方式三:异步Promise操作文件


// 3.方式三: Promise方式
fs.promises.stat("../foo.txt").then(state => {
  console.log(state);
}).catch(err => {
  console.log(err);
})
console.log("后续代码执行");


获取文件描述信息


const fs = require("fs");
    fs.stat("./01.hello.txt", (err, info) => {
      console.log(info)
      console.log(info.isFile())// 判断他是否为文件
      console.log(info.isDirectory())// 判断他是否为文件夹
    })


网络异常,图片无法展示
|


文件描述符


在 POSIX 系统上,对于每个进程,内核都维护着一张当前打开着的文件和资源的表格。

每个打开的文件都分配了一个称为文件描述符的简单的数字标识符。


在系统层,所有文件系统操作都使用这些文件描述符来标识和跟踪每个特定的文件。


Windows 系统使用了一个虽然不同但概念上类似的机制来跟踪资源。


为了简化用户的工作,Node.js 抽象出操作系统之间的特定差异,并为所有打开的文件分配一个数字型的文件描述符


const fs = require("fs");
    fs.open("./01.hello.txt", (err, fd) => {
      if (err) {
        console.log(err)
      } else {
        console.log(fd) // fd是一个数字。
        fs.promise.readFile(fd).then(res => {
          console.log(res)
        })
      }
    })


文件读写


fs.readFile(path[, options], callback):读取文件的内容;

fs.writeFile(file, data[, options], callback):在文件中写入内容;


const fs = require("fs");
    fs.writeFile("./01.hello.txt", "加入文件", { encoding: 'utf-8', flag: 'a+' }, (err, res) => {
      if (err) {
        console.log(err)
      } else {
        console.log(res)
      }
    })


调用读写API很简单就可以操作文件,下面我们来说明一些options选项。


encoding:指定编码格式。注意如果读取文件和写入文件的编码格式不同,将会乱码。一般都采用utf-8编码。如果文件读取不指定编码格式,那么它将返回Buffer数据。


flag: 用于指定文件写入的方式。带有+的flag都可以读写。除了r+文件不存在,读取和写入会报出异常,其他的+flag都可以自动创建。


网络异常,图片无法展示
|


文件夹操作


  • 使用fs.mkdir()或fs.mkdirSync()创建一个新文件夹。


const dirname = './zh';
    if (!fs.existsSync(dirname)) { // 判断文件夹是否存在
      fs.mkdir(dirname, err => {
        console.log(err);
      });
    }


  • fs.readdir(), fs.readdirSync()读取文件夹中的所有文件和文件夹


fs.readdir(dirname, (err, files) => {
      console.log(files);
    });


  • rename()重命名文件夹


fs.rename("./zh", "./llm", err => {
      console.log(err);
    })


兄弟们,熟练掌握文件操作,可以写很多方便的脚本。


相关文章
|
5天前
|
缓存 负载均衡 JavaScript
构建高效后端服务:Node.js与Express框架实践
在数字化时代的浪潮中,后端服务的重要性不言而喻。本文将通过深入浅出的方式介绍如何利用Node.js及其强大的Express框架来搭建一个高效的后端服务。我们将从零开始,逐步深入,不仅涉及基础的代码编写,更会探讨如何优化性能和处理高并发场景。无论你是后端新手还是希望提高现有技能的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
17天前
|
Web App开发 JavaScript 前端开发
探索后端开发:Node.js与Express的完美结合
【10月更文挑战第33天】本文将带领读者深入了解Node.js和Express的强强联手,通过实际案例揭示它们如何简化后端开发流程,提升应用性能。我们将一起探索这两个技术的核心概念、优势以及它们如何共同作用于现代Web开发中。准备好,让我们一起开启这场技术之旅!
32 0
|
17天前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实践
【10月更文挑战第33天】在数字化时代的浪潮中,后端服务的效率和可靠性成为企业竞争的关键。本文将深入探讨如何利用Node.js和Express框架构建高效且易于维护的后端服务。通过实践案例和代码示例,我们将揭示这一组合如何简化开发流程、优化性能,并提升用户体验。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。
|
1月前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
1月前
|
开发框架 JavaScript 前端开发
使用 Node.js 和 Express 构建 Web 应用
【10月更文挑战第2天】使用 Node.js 和 Express 构建 Web 应用
|
2月前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实战指南
【9月更文挑战第6天】在数字化时代的潮流中,后端开发作为支撑现代Web和移动应用的核心,其重要性不言而喻。本文将深入浅出地介绍如何使用Node.js及其流行的框架Express来搭建一个高效、可扩展的后端服务。通过具体的代码示例和实践技巧,我们将探索如何利用这两个强大的工具提升开发效率和应用性能。无论你是后端开发的新手还是希望提高现有项目质量的老手,这篇文章都将为你提供有价值的见解和指导。
|
22天前
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。
|
29天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的完美结合
【10月更文挑战第21天】本文将引导你走进Node.js和Express框架的世界,探索它们如何共同打造一个高效、可扩展的后端服务。通过深入浅出的解释和实际代码示例,我们将一起理解这一组合的魅力所在,并学习如何利用它们来构建现代Web应用。
48 1
|
19天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的融合之道
【10月更文挑战第31天】在追求快速、灵活和高效的后端开发领域,Node.js与Express框架的结合如同咖啡遇见了奶油——完美融合。本文将带你探索这一组合如何让后端服务搭建变得既轻松又充满乐趣,同时确保你的应用能够以光速运行。
24 0
|
1月前
|
JSON JavaScript 前端开发
Node.js Express 框架
10月更文挑战第7天
30 2
下一篇
无影云桌面