Au cours du processus de développement, Node.js est souvent utilisé, qui utilise les capacités fournies par la V8 pour étendre les capacités de JS. Dans Node.js, nous pouvons utiliser le module path qui n'existe pas dans JS Afin que nous puissions mieux connaître l'application, jetons-y un coup d'œil ~
La version Node.js de cet article est 16.14.0. , et le code source de cet article provient d'ici Version. J'espère qu'après avoir lu cet article, il sera utile à tout le monde de lire le code source.
Path est utilisé pour traiter les chemins des fichiers et des répertoires. Ce module fournit des fonctions d'outils que les développeurs peuvent facilement développer pour nous aider à faire des jugements de chemin complexes et à améliorer l'efficacité du développement. Par exemple :
Configurer les alias dans le projet La configuration de l'alias nous permet de référencer plus facilement les fichiers et d'éviter de chercher vers le haut étape par étape.
réaimer : { pseudo : { // __dirname chemin du répertoire 'src' où se trouve le fichier actuel : path.resolve(__dirname, './src'), // répertoire de travail actuel de process.cwd '@' : path.join(process.cwd(), 'src'), }, }
Dans webpack, le chemin de sortie du fichier peut également être généré vers l'emplacement spécifié via notre propre configuration.
module.exports = { entrée : './path/to/my/entry/file.js', sortir: { chemin : chemin.resolve(__dirname, 'dist'), nom de fichier : 'mon-premier-webpack.bundle.js', }, };
Ou pour les opérations sur les dossiers,
let fs = require("fs"); let chemin = require("chemin"); // Supprime le dossier let deleDir = (src) => { // Lire le dossier let children = fs.readdirSync(src); enfants.forEach(item => { laissez childpath = path.join(src, item); // Vérifiez si le fichier existe let file = fs.statSync(childpath).isFile(); si (fichier) { // Supprime le fichier s'il existe fs.unlinkSync(childpath) } autre { //Continuer à détecter le dossier deleDir(childpath) } }) // Supprime le dossier vide fs.rmdirSync(src) } deleDir("../floor")
comprend brièvement les scénarios d'utilisation de path. Ensuite, nous étudierons son mécanisme d'exécution et comment il est implémenté en fonction de son utilisation.
Lorsque le module path est introduit et que la fonction outil de path est appelée, la logique de traitement du module natif sera entrée.
Utilisez la fonction _load
pour utiliser le nom du module que vous avez introduit comme ID afin de déterminer que le module à charger est un module JS natif. Après cela, la fonction loadNativeModule
sera utilisée pour utiliser l'identifiant pour trouver le code ASCII correspondant à partir de _source
(. la chaîne de code source qui enregistre le module JS natif). Les données sont chargées dans le module JS natif.
Exécutez le fichier lib/path.js et utilisez le processus pour déterminer le système d'exploitation. Selon le système d'exploitation, il peut y avoir un traitement différentiel des caractères d'exploitation dans le traitement du fichier, mais la méthode est à peu près la même. Après le traitement, il est renvoyé. l'appelant.
La résolution renvoie le chemin absolu du chemin actuel.
La résolution épisse plusieurs paramètres en séquence pour générer un nouveau chemin absolu.
résoudre(...arguments) { laissez-résoluDevice = ''; laissez-résoluTail = ''; laissez solveAbsolute = false ; // Détecte les paramètres de droite à gauche pour (let i = args.length - 1; i >= -1; i--) { ... } //Chemin normalisé solveTail = normalizeString(resolvedTail, !resolvedAbsolute, '\', isPathSeparator); retourner résoluAbsolu ? `${resolvedDevice}\${resolvedTail}` : `${appareil résolu}${queue résolu}` || '.'; }
Obtenez le chemin en fonction des paramètres, parcourez les paramètres reçus, commencez l'épissage lorsque la longueur des paramètres est supérieure ou égale à 0, effectuez une vérification sans chaîne sur le chemin épissé, s'il y a des paramètres qui ne correspondent pas , throw new ERR_INVALID_ARG_TYPE(name, 'string', value)
, si les exigences sont remplies, la longueur du chemin sera jugée S'il y a une valeur, += path sera utilisé pour l'étape suivante.
laisser le chemin ; si (je >= 0) { chemin = args[i]; // internes/validateurs validateString(chemin, 'chemin'); // Si la longueur du chemin est 0, il sortira directement de la boucle for du bloc de code ci-dessus if (path.length === 0) { continuer; } } sinon si (resolvedDevice.length === 0) { //La longueur de wantedDevice est 0, attribuez la valeur à path comme répertoire de travail actuel path = process.cwd(); } autre { // Attribue la valeur à l'objet d'environnement ou au chemin du répertoire de travail actuel = process.env[`=${resolvedDevice}`] || process.cwd(); if (chemin === non défini || (StringPrototypeToLowerCase(StringPrototypeSlice(chemin, 0, 2)) !== StringPrototypeToLowerCase (appareil résolu) && StringPrototypeCharCodeAt(chemin, 2) === CHAR_BACKWARD_SLASH)) { //Jugez le chemin vers les chemins non vides et absolus pour obtenir le chemin path = `${resolvedDevice}\`; } }
Essayez de faire correspondre le chemin racine, déterminez s'il n'y a qu'un seul séparateur de chemin (« ») ou si le chemin est un chemin absolu, puis marquez le chemin absolu et définissez rootEnd
sur 1 (indice). Si le deuxième élément est toujours un séparateur de chemin (« »), définissez la valeur d'interception sur 2 (indice) et utilisez last
pour enregistrer la valeur d'interception pour un jugement ultérieur.
Continuez à déterminer si le troisième élément est un séparateur de chemin (« »). Si tel est le cas, il s'agit d'un chemin absolu et l'identifiant d'interception rootEnd
est 1 (indice), mais il peut également s'agir d'un chemin UNC (servernamesharename , nom du serveur nom du serveur). nom de la ressource partagée sharename). S'il y a d'autres valeurs, la valeur interceptée continuera à incrémenter et à lire les valeurs suivantes, et utilisera firstPart
pour enregistrer la valeur du troisième bit afin que la valeur puisse être obtenue lors de l'épissage du répertoire, et conservera les dernières valeurs interceptées. cohérent pour mettre fin au jugement.
const len = chemin.longueur; let rootEnd = 0; // Indice de fin d'interception de chemin let device = ''; // Racine du disque D:, C: let isAbsolute = false; // S'il s'agit du chemin racine du disque const code = StringPrototypeCharCodeAt(path, 0); // la longueur du chemin est 1 si (len === 1) { // Il n'y a qu'un seul séparateur de chemin pour le chemin absolu if (isPathSeparator(code)) { racineFin = 1 ; estAbsolu = vrai ; } } sinon if (isPathSeparator(code)) { // Peut être une racine UNC, commençant par un délimiteur , dont au moins un est une sorte de chemin absolu (UNC ou autre) estAbsolu = vrai ; // Commencez à faire correspondre le séparateur de double chemin if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { soit j = 2; soit dernier = j; // Correspond à un ou plusieurs délimiteurs non-chemin while (j < len && !isPathSeparator(StringPrototypeCharCodeAt(chemin, j))) { j++; } if (j < len && j !== dernier) { const firstPart = StringPrototypeSlice(chemin, dernier, j); dernier = j; // Correspond à un ou plusieurs séparateurs de chemin while (j < len && isPathSeparator(StringPrototypeCharCodeAt(chemin, j))) { j++; } if (j < len && j !== dernier) { dernier = j; tandis que (j < len && !isPathSeparator(StringPrototypeCharCodeAt(chemin, j))) { j++; } si (j === len || j !== dernier) { appareil = `\\${firstPart}\${StringPrototypeSlice(path, last, j)}`; racineFin = j; } } } } autre { racineFin = 1 ; } // Détection du répertoire racine du disque correspondant à un exemple : D:, C: } sinon if (isWindowsDeviceRoot(code) && StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) { périphérique = StringPrototypeSlice (chemin, 0, 2); racineFin = 2 ; if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) { estAbsolu = vrai ; racineFin = 3 ; } }
Détectez le chemin et générez-le, vérifiez si le répertoire racine du disque existe ou déterminez si resolvedAbsolute
est un chemin absolu.
// Détecte le répertoire racine du disque if (device.length > 0) { // solveDevice a une valeur if (resolvedDevice.length > 0) { si (StringPrototypeToLowerCase(device) !== StringPrototypeToLowerCase (appareil résolu)) continuer; } autre { // RésoluDevice n'a aucune valeur et se voit attribuer la valeur du répertoire racine du disque résoluDevice = périphérique ; } } // Chemin absolu if (resolvedAbsolute) { // Il existe une boucle de fin si le répertoire racine du disque existe (resolvedDevice.length > 0) casser; } autre { // Récupère le préfixe du chemin pour l'épissage résoluTail = `${StringPrototypeSlice(path, rootEnd)}\${resolvedTail}` ; résoluAbsolute = isAbsolute ; if (isAbsolute &&solvingDevice.length > 0) { // La boucle se termine lorsque la racine du disque existe break; } }
join effectue un épissage de chemin en fonction des fragments de chemin entrants
Recevez plusieurs paramètres, utilisez des séparateurs spécifiques comme délimiteurs pour connecter tous les paramètres de chemin entre eux et générez un nouveau chemin normalisé.
Après avoir reçu les paramètres, vérifiez-les. S'il n'y a pas de paramètres, il renverra directement '.' Sinon, il traversera et vérifiera chaque paramètre via la méthode validateString
intégrée, throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
join
fonction du caractère d'échappement est que lorsqu'il est utilisé seul, il est considéré comme échappant à la chaîne après la barre oblique, donc des doubles barres obliques inverses sont utilisées pour échapper à la barre oblique inverse ('').
Enfin, la chaîne concaténée est vérifiée et renvoyée au format.
si (arguments longueur === 0) retour '.'; laissez rejoindre; laissez firstPart; // Détecte les paramètres de gauche à droite pour (let i = 0; i < args.length; ++i) { const arg = args[je]; // internes/validateurs validateString(arg, 'chemin'); si (longueur d'argument > 0) { if (rejoint === non défini) // Attribue la première chaîne à join et utilise la variable firstPart pour enregistrer la première chaîne pour une utilisation ultérieure join = firstPart = arg; autre // joint a une valeur, effectue += opération d'épissage joint += `\${arg}` ; } } if (rejoint === non défini) return '.';
Sous le système de fenêtres, le traitement du chemin réseau est requis en raison de l'utilisation de la barre oblique inverse ('') et du chemin UNC (faisant principalement référence au nom complet Windows 2000 des ressources sur le réseau local), (''). représente est un format de chemin réseau, donc la méthode join
montée sous win32 interceptera par défaut.
Si une barre oblique inverse ('') correspond, slashCount
sera incrémenté. Tant qu'il y aura plus de deux barres obliques inverses ('') correspondantes, le chemin épissé sera intercepté et épissé manuellement et échappé. '').
laissez needReplace = true; laissez slashCount = 0 ; // Extrayez le code de la première chaîne de la séquence selon StringPrototypeCharCodeAt et faites-le correspondre avec le code défini via la méthode isPathSeparator if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) { ++slashCount; const firstLen = firstPart.length; si (firstLen > 1 && isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) { ++slashCount; si (firstLen > 2) { if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2))) ++slashCount; autre { needReplace = faux ; } } } } si (besoinsRemplacer) { while (slashCount < join.length && isPathSeparator(StringPrototypeCharCodeAt(joined, slashCount))) { slashCount++; } si (slashCount >= 2) joins = `\${StringPrototypeSlice(joined, slashCount)}`; }
Tri des résultats d'exécution
solve | join | |
---|---|---|
n'a pas de paramètres | .Le | chemin absolu du fichier actuel.Les |
absolu.Le | ||
chemin | absoludu fichier actuel est épissé | dans l'ordre. |
intégré au chemin absolu des | chemins non absolus suivants. | Le|
post-paramètre de chemin est un | paramètre de chemin absolu. Le chemin écrase le chemin absolu du fichier actuel et écrase | le chemin épissé par le. | pré-paramètres.Le
premier paramètre est (./) | et a les paramètres suivants.Le paramètre d'épissage de chemin absolu du fichier actuel n'a pas de paramètres suivants. Le chemin absolu du fichier actuel est Le chemin | a les paramètres suivants et le chemin est épissé. par les paramètres suivants n'a pas de paramètres suivants. (./) |
Le post-paramètre a (./) | Le paramètre d'épissage du chemin absolu analysé | a des paramètres suivants. Le chemin épissé n'a pas de paramètres suivants, et l'épissage (/) |
Le. le premier paramètre est (../) | et il y a des paramètres suivants. Les paramètres d'épissage après le répertoire de dernier niveau couvrant le chemin absolu du fichier actuel n'ont pas de paramètres suivants | . . Épissage Il n'y a pas de paramètres suivants pour les paramètres suivants (../) |
Le post-paramètre a (../ | ). Le répertoire de niveau supérieur où (../) apparaît sera écrasé. écrasé.Le répertoire de niveau supérieur sera écrasé.Après avoir renvoyé (/), les paramètres suivants seront épissés et | le répertoire supérieur qui apparaît (../) sera écrasé. Le nombre de couches apparaissant dans le suffixe sera couvert. .Une fois le répertoire supérieur écrasé, le |
lu. Après le code source, la méthode resolve
traitera les paramètres, considérera la forme du chemin et rejettera le chemin absolu à la fin. Lors de son utilisation, si vous effectuez des opérations telles que des fichiers, il est recommandé d'utiliser la méthode resolve
. En comparaison, la méthode resolve
renverra un chemin même s'il n'y a aucun paramètre que l'utilisateur doit utiliser, et le chemin sera traité. pendant le processus d'exécution. La méthode join
effectue uniquement un épissage standardisé des paramètres entrants, ce qui est plus pratique pour générer un nouveau chemin et peut être créé selon les souhaits de l'utilisateur. Cependant, chaque méthode a ses avantages. Vous devez choisir la méthode appropriée en fonction de vos propres scénarios d'utilisation et des besoins de votre projet.