聊聊Node.js path模块中的常用工具函数

本篇文章带大家聊聊node中的path模块,介绍一下path的常见使用场景、执行机制,以及常用工具函数,希望对大家有所帮助!

聊聊Node.js path模块中的常用工具函数

在开发过程中,会经常用到 Node.js  ,它利用 V8 提供的能力,拓展了 JS 的能力。而在 Node.js 中,我们可以使用 JS 中本来不存在的 path 模块,为了我们更加熟悉的运用,让我们一起来了解一下吧~

本文 Node.js 版本为 16.14.0,本文的源码来自于此版本。希望大家阅读本文后,会对大家阅读源码有所帮助。

path 的常见使用场景

Path 用于处理文件和目录的路径,这个模块中提供了一些便于开发者开发的工具函数,来协助我们进行复杂的路径判断,提高开发效率。例如:

在项目中配置别名,别名的配置方便我们对文件更简便的引用,避免深层级逐级向上查找。

reslove: {  alias: {    // __dirname 当前文件所在的目录路径    'src': path.resolve(__dirname, './src'),    // process.cwd 当前工作目录    '@': path.join(process.cwd(), 'src'),  },}

登录后复制

在 webpack 中,文件的输出路径也可以通过我们自行配置生成到指定的位置。

module.exports = {  entry: './path/to/my/entry/file.js',  output: {    path: path.resolve(__dirname, 'dist'),    filename: 'my-first-webpack.bundle.js',  },};

登录后复制

又或者对于文件夹的操作

let fs = require("fs");let path = require("path");// 删除文件夹let deleDir = (src) => {    // 读取文件夹    let children = fs.readdirSync(src);    children.forEach(item => {        let childpath = path.join(src, item);        // 检查文件是否存在        let file = fs.statSync(childpath).isFile();        if (file) {            // 文件存在就删除            fs.unlinkSync(childpath)        } else {            // 继续检测文件夹            deleDir(childpath)        }    })    // 删除空文件夹    fs.rmdirSync(src)}deleDir("../floor")

登录后复制

简单的了解了一下 path 的使用场景,接下来我们根据使用来研究一下它的执行机制,以及是怎么实现的。

path 的执行机制

1.png

引入 path 模块,调用 path 的工具函数的时候,会进入原生模块的处理逻辑。

使用  _load  函数根据你引入的模块名作为 ID,判断要加载的模块是原生 JS 模块后,会通过 loadNativeModule 函数,利用 id 从 _source (保存原生JS模块的源码字符串转成的 ASCII 码)中找到对应的数据加载原生 JS 模块。

执行 lib/path.js 文件,利用 process 判断操作系统,根据操作系统的不同,在其文件处理上可能会存在操作字符的差异化处理,但方法大致一样,处理完后返回给调用方。

常用工具函数简析

resolve 返回当前路径的绝对路径

resolve 将多个参数,依次进行拼接,生成新的绝对路径。

resolve(...args) {  let resolvedDevice = '';  let resolvedTail = '';  let resolvedAbsolute = false;  // 从右到左检测参数  for (let i = args.length - 1; i >= -1; i--) {    ......  }  // 规范化路径  resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\', isPathSeparator);  return resolvedAbsolute ?    `${resolvedDevice}\${resolvedTail}` :    `${resolvedDevice}${resolvedTail}` || '.';}

登录后复制

2.png

根据参数获取路径,对接收到的参数进行遍历,参数的长度大于等于 0 时都会开始进行拼接,对拼接好的 path 进行非字符串校验,有不符合的参数则抛出 throw new ERR_INVALID_ARG_TYPE(name, ‘string’, value), 符合要求则会对 path 进行长度判断,有值则 +=path 做下一步操作。

let path;if (i >= 0) {  path = args[i];  // internal/validators  validateString(path, 'path');  // path 长度为 0 的话,会直接跳出上述代码块的 for 循环  if (path.length === 0) {    continue;  }} else if (resolvedDevice.length === 0) {  // resolvedDevice 的长度为 0,给 path 赋值为当前工作目录  path = process.cwd();} else {  // 赋值为环境对象或者当前工作目录  path = process.env[`=${resolvedDevice}`] || process.cwd();  if (path === undefined ||      (StringPrototypeToLowerCase(StringPrototypeSlice(path, 0, 2)) !==      StringPrototypeToLowerCase(resolvedDevice) &&      StringPrototypeCharCodeAt(path, 2) === CHAR_BACKWARD_SLASH)) {    // 对 path 进行非空与绝对路径判断得出 path 路径    path = `${resolvedDevice}\`;  }}

登录后复制

3.png

尝试匹配根路径,判断是否是只有一个路径分隔符 (”) 或者 path 为绝对路径,然后给绝对路径打标,并把 rootEnd 截取标识设为 1 (下标)。第二项若还是路径分隔符 (”) ,就定义截取值为 2 (下标),并用 last 保存截取值,以便后续判断使用。

继续判断第三项是否是路径分隔符 (”),如果是,那么为绝对路径,rootEnd 截取标识为 1 (下标),但也有可能是 UNC 路径 ( servernamesharename,servername 服务器名。sharename 共享资源名称)。如果有其他值,截取值会继续进行自增读取后面的值,并用 firstPart 保存第三位的值,以便拼接目录时取值,并把 last 和截取值保持一致,以便结束判断。

const len = path.length;let rootEnd = 0; // 路径截取结束下标let device = ''; // 磁盘根 D:、C:let isAbsolute = false; // 是否是磁盘根路径const code = StringPrototypeCharCodeAt(path, 0);// path 长度为 1if (len === 1) {  // 只有一个路径分隔符  为绝对路径  if (isPathSeparator(code)) {    rootEnd = 1;    isAbsolute = true;  }} else if (isPathSeparator(code)) {  // 可能是 UNC 根,从一个分隔符  开始,至少有一个它就是某种绝对路径(UNC或其他)  isAbsolute = true;  // 开始匹配双路径分隔符  if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {    let j = 2;    let last = j;    // 匹配一个或多个非路径分隔符    while (j  2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) {    isAbsolute = true;    rootEnd = 3;  }}

登录后复制

检测路径并生成,检测磁盘根目录是否存在或解析 resolvedAbsolute 是否为绝对路径。

// 检测磁盘根目录if (device.length > 0) {  // resolvedDevice 有值  if (resolvedDevice.length > 0) {    if (StringPrototypeToLowerCase(device) !==        StringPrototypeToLowerCase(resolvedDevice))      continue;  } else {    // resolvedDevice 无值并赋值为磁盘根目录    resolvedDevice = device;  }}// 绝对路径if (resolvedAbsolute) {  // 磁盘根目录存在结束循环  if (resolvedDevice.length > 0)    break;} else {  // 获取路径前缀进行拼接  resolvedTail =    `${StringPrototypeSlice(path, rootEnd)}\${resolvedTail}`;  resolvedAbsolute = isAbsolute;  if (isAbsolute && resolvedDevice.length > 0) {    // 磁盘根存在便结束循环    break;  }}

登录后复制

join 根据传入的 path 片段进行路径拼接

4.png

接收多个参数,利用特定分隔符作为定界符将所有的 path 参数连接在一起,生成新的规范化路径。

接收参数后进行校验,如果没有参数的话,会直接返回 ‘.’ ,反之进行遍历,通过内置 validateString 方法校验每个参数,如有一项不合规则直接  throw new ERR_INVALID_ARG_TYPE(name, ‘string’, value);

window 下为反斜杠 (”) , 而 linux 下为正斜杠 (‘/’),这里是 join 方法区分操作系统的一个不同点,而反斜杠 (”) 有转义符的作用,单独使用会被认为是要转义斜杠后面的字符串,故此使用双反斜杠转义出反斜杠 (”) 使用。

最后进行拼接后的字符串校验并格式化返回。

if (args.length === 0)    return '.';let joined;let firstPart;// 从左到右检测参数for (let i = 0; i  0) {    if (joined === undefined)      // 把第一个字符串赋值给 joined,并用 firstPart 变量保存第一个字符串以待后面使用      joined = firstPart = arg;    else      // joined 有值,进行 += 拼接操作      joined += `\${arg}`;  }}if (joined === undefined)  return '.';

登录后复制

在 window 系统下,因为使用反斜杠 (”) 和 UNC (主要指局域网上资源的完整 Windows 2000 名称)路径的缘故,需要进行网络路径处理,(”) 代表的是网络路径格式,因此在 win32 下挂载的join 方法默认会进行截取操作。

如果匹配得到反斜杠 (”),slashCount 就会进行自增操作,只要匹配反斜杠 (”) 大于两个就会对拼接好的路径进行截取操作,并手动拼接转义后的反斜杠 (”)。

let needsReplace = true;let slashCount = 0;// 根据 StringPrototypeCharCodeAt 对首个字符串依次进行 code 码提取,并通过 isPathSeparator 方法与定义好的 code 码进行匹配if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) {  ++slashCount;  const firstLen = firstPart.length;  if (firstLen > 1 &&      isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) {    ++slashCount;    if (firstLen > 2) {      if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2)))        ++slashCount;      else {        needsReplace = false;      }    }  }}if (needsReplace) {  while (slashCount = 2)    joined = `\${StringPrototypeSlice(joined, slashCount)}`;}

登录后复制

执行结果梳理

resolve join

无参数当前文件的绝对路径.参数无绝对路径当前文件的绝对路径按顺序拼接参数拼接成的路径首个参数为绝对路径参数路径覆盖当前文件绝对路径并拼接后续非绝对路径拼接成的绝对路径后置参数为绝对路径参数路径覆盖当前文件绝对路径并覆盖前置参数拼接成的路径首个参数为(./)有后续参数,当前文件的绝对路径拼接参数
无后续参数,当前文件的绝对路径有后续参数,后续参数拼接成的路径
无后续参数,(./)后置参数有(./)解析后的绝对路径拼接参数有后续参数,拼接成的路径拼接后续参数
无后续参数,拼接(/)首个参数为(../)有后续参数,覆盖当前文件的绝对路径的最后一级目录后拼接参数
无后续参数,覆盖当前文件的绝对路径的最后一级目录有后续参数,拼接后续参数
无后续参数,(../)后置参数有(../)出现(../)的上层目录会被覆盖,后置出现多少个,就会覆盖多少层,上层目录被覆盖完后,返回(/),后续参数会拼接出现(../)的上层目录会被覆盖,后置出现多少个,就会覆盖多少层,上层目录被覆盖完后,会进行参数拼接

总结

阅读了源码之后,resolve 方法会对参数进行处理,考虑路径的形式,在最后抛出绝对路径。在使用的时候,如果是进行文件之类的操作,推荐使用 resolve 方法,相比来看, resolve 方法就算没有参数也会返回一个路径,供使用者操作,在执行过程中会进行路径的处理。而 join 方法只是对传入的参数进行规范化拼接,对于生成一个新的路径比较实用,可以按照使用者意愿创建。不过每个方法都有优点,要根据自己的使用场景以及项目需求,去选择合适的方法。

更多node相关知识,请访问:nodejs 教程!

以上就是聊聊Node.js path模块中的常用工具函数的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2700841.html

(0)
上一篇 2025年3月7日 19:10:28
下一篇 2025年2月28日 15:25:05

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 聊聊node+express怎么操作cookie

    node+express怎么操作cookie?下面本篇文章就来给大家介绍一下用nodejs操作cookie的方法,希望对大家有所帮助! Cookie:有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进…

    2025年3月7日 编程技术
    200
  • 聊聊node+multiparty怎么实现文件上传

    利用node怎么实现文件上传?下面本篇文章就来给大家介绍一下node结合multiparty实现文件上传的方法,希望对大家有所帮助! 文件上传是每个项目中大概必不可少的操作,今天我们用node实现一个文件上传模块。 1.模块 npm i m…

    2025年3月7日
    200
  • 一文详解Nodejs中怎么读写文件

    node中怎么操作文件?下面本篇文章带大家聊聊怎么使用nodejs读写文件,希望对大家有所帮助! 操作文件是服务端一个基础的功能,也是做后端开发的必备能力之一。 操作文件主要包括读和写。而这些功能 Nodejs 都已经提供了对应的方法。只要…

    2025年3月7日
    200
  • 推荐11个受欢迎的Node.js 框架,快放入收藏夹吧!

    Node.JS是最流行的开源JavaScript运行时框架之一,并具有在浏览器之外建立代码的跨平台能力。知名开发者Alex Ivanovs自2005年就开始从事Web开发工作,近日,他根据前端构架调查、开发者调查报告以及个人项目经验,总结出…

    2025年3月7日 编程技术
    200
  • 总结分享了解nodejs的几个关键节点

    本文是个人在实际开发和学习中对nodejs的一些理解,现整理出来方便日后查阅,如果能给您启发将不胜荣幸。 非阻塞I/O I/O:即 Input / Output,一个系统的输入和输出。 一个系统可以理解为一个个体,比如说一个人,你说话就是输…

    2025年3月7日 编程技术
    200
  • 进程和线程如何理解?Node.js中的进程和线程是怎样的?

    线程和进程是计算机操作系统的基础概念,在程序员中属于高频词汇,那如何理解呢?node中的进程和线程又是怎样的呢?下面本篇文章就来一起了解一下,希望对大家有所帮助! 一、进程和线程 1.1、专业性文字定义 进程(Process),进程是计算机…

    2025年3月7日 编程技术
    200
  • node.js gm是什么

    gm是基于node.js的图片处理插件,它封装了图片处理工具GraphicsMagick(GM)和ImageMagick(IM),可使用spawn的方式调用。gm插件不是node默认安装的,需执行“npm install gm -S”进行安…

    2025年3月7日 编程技术
    200
  • webpack是基于node.js的吗

    webpack是基于node.js的。webpack是一个用于现代JavaScript应用程序的静态模块打包工具,是基于node.js开发的,使用时需要有node.js组件支持;需要使用npm或者cnpm进行安装,语法“cnpm insta…

    2025年3月7日
    200
  • 深入解析NodeJS中的进程管理

    熟悉 js 的朋友都知道,js 是单线程的,在 Node 中,采用的是 多进程单线程 的模型。由于javascript单线程的限制,在多核服务器上,我们往往需要启动多个进程才能最大化服务器性能。 Node.js 进程集群可用于运行多个 No…

    2025年3月7日 编程技术
    200
  • 一文了解Node中的文件模块和核心模块

    本篇文章带大家了解一下node中的文件模块和核心模块,聊聊文件模块的查找和文件模块的编译执行、javascript与c/c++ 核心模块的编译执行,希望对大家有所帮助! 在我们使用 node 进行日常开发时,经常会使用 require 导入…

    2025年3月7日 编程技术
    200

发表回复

登录后才能评论