Durante o processo de desenvolvimento, o Node.js é frequentemente usado, que usa os recursos fornecidos pelo V8 para expandir os recursos do JS. Em Node.js, podemos usar o módulo path que não existe em JS. Para nos familiarizarmos mais com o aplicativo, vamos dar uma olhada nele ~
A versão Node.js deste artigo é 16.14.0. , e o código-fonte deste artigo vem daqui Versão. Espero que depois de ler este artigo, seja útil para todos lerem o código-fonte.
Path é usado para processar os caminhos de arquivos e diretórios. Este módulo fornece algumas funções de ferramenta que são convenientes para os desenvolvedores desenvolverem para nos ajudar a fazer julgamentos de caminhos complexos e melhorar a eficiência do desenvolvimento. Por exemplo:
Configurar aliases no projeto A configuração do alias facilita a referência de arquivos e evita a busca passo a passo.
reamar: { apelido: { // __dirname caminho do diretório 'src' onde o arquivo atual está localizado: path.resolve(__dirname, './src'), // process.cwd diretório de trabalho atual '@': path.join(process.cwd(), 'src'), }, }
No webpack, o caminho de saída do arquivo também pode ser gerado para o local especificado através de nossa própria configuração.
módulo.exportações = { entrada: './caminho/para/minha/entrada/arquivo.js', saída: { caminho: path.resolve(__dirname, 'dist'), nome do arquivo: 'meu-primeiro-webpack.bundle.js', }, };
Ou para operações de pasta
let fs = require("fs"); deixe caminho = exigir("caminho"); // Exclua a pasta let deleDir = (src) => { // Leia a pasta let children = fs.readdirSync(src); filhos.forEach(item => { deixe caminho filho = path.join(src, item); // Verifica se o arquivo existe let file = fs.statSync(childpath).isFile(); se (arquivo) { // Exclua o arquivo se ele existir fs.unlinkSync(childpath) } outro { //Continua detectando a pasta deleDir(childpath) } }) // Exclua a pasta vazia fs.rmdirSync(src) } deleDir("../floor")
entende brevemente os cenários de uso do caminho. A seguir, estudaremos seu mecanismo de execução e como ele é implementado com base em seu uso.
Quando o módulo path é introduzido e a função da ferramenta path é chamada, a lógica de processamento do módulo nativo será inserida.
Use a função _load
para usar o nome do módulo que você introduziu como ID para determinar se o módulo a ser carregado é um módulo JS nativo. Depois disso, a função loadNativeModule
será usada para usar o id para encontrar o código ASCII correspondente de _source
(. a string do código-fonte que salva o módulo JS nativo). Os dados são carregados no módulo JS nativo.
Execute o arquivo lib/path.js e use o processo para determinar o sistema operacional Dependendo do sistema operacional, pode haver processamento diferencial de caracteres operacionais no processamento do arquivo, mas o método é aproximadamente o mesmo. Após o processamento, ele é retornado. o chamador.
resolve retorna o caminho absoluto do caminho atual
resolve emenda vários parâmetros em sequência para gerar um novo caminho absoluto.
resolver(...args) { deixe resolvidoDevice = ''; deixe resolvidoTail = ''; deixe resolvidoAbsoluto = falso; // Detecta parâmetros da direita para a esquerda for (let i = args.length - 1; i >= -1; i--) { ... } //Caminho normalizado resolveTail = normalizeString(resolvedTail, !resolvedAbsolute, '\', isPathSeparator); retornar resolvidoAbsoluto? `${resolvedDevice}\${resolvedTail}` : `${resolvedDevice}${resolvedTail}` || '.'; }
Obtenha o caminho de acordo com os parâmetros, percorra os parâmetros recebidos, inicie a emenda quando o comprimento dos parâmetros for maior ou igual a 0, execute a verificação de não string no caminho emendado, se houver algum parâmetro que não corresponda , throw new ERR_INVALID_ARG_TYPE(name, 'string', value)
, se os requisitos forem atendidos, o comprimento do caminho será julgado. Se houver um valor, += path será usado para a próxima etapa.
deixe caminho; se (eu >= 0) { caminho = args[i]; // interno/validadores validarString(caminho, 'caminho'); // Se o comprimento do caminho for 0, ele saltará diretamente para fora do loop for do bloco de código acima if (path.length === 0) { continuar; } } else if (resolvedDevice.length === 0) { //O comprimento de resolveDevice é 0, atribua o valor ao path como o diretório de trabalho atual path = process.cwd(); } outro { // Atribua o valor ao objeto de ambiente ou ao diretório de trabalho atual path = process.env[`=${resolvedDevice}`] || process.cwd(); if (caminho === indefinido || (StringPrototypeToLowerCase(StringPrototypeSlice(caminho, 0, 2)) !== StringPrototypeToLowerCase(resolvidoDevice) && StringPrototypeCharCodeAt(caminho, 2) === CHAR_BACKWARD_SLASH)) { //Julgue o caminho para caminhos não vazios e absolutos para obter o caminho path = `${resolvedDevice}\`; } }
Tente corresponder o caminho raiz, determine se há apenas um separador de caminho ('') ou se o caminho é um caminho absoluto, marque o caminho absoluto e defina rootEnd
como 1 (subscrito). Se o segundo item ainda for um separador de caminho (''), defina o valor de interceptação como 2 (subscrito) e use last
para salvar o valor de interceptação para julgamento subsequente.
Continue a determinar se o terceiro item é um separador de caminho (''). Nesse caso, é um caminho absoluto e o identificador de interceptação rootEnd
é 1 (subscrito), mas também pode ser um caminho UNC (servernamesharename). , nome do servidor nome do servidor). nome do recurso compartilhado). Se houver outros valores, o valor interceptado continuará a incrementar e ler os seguintes valores, e usar firstPart
para salvar o valor do terceiro bit para que o valor possa ser obtido ao emendar o diretório, e manter os últimos valores interceptados consistente para encerrar o julgamento.
const len = caminho.comprimento; let rootEnd = 0; // Subscrito final da interceptação do caminho let device = ''; let isAbsolute = false; // Se é o caminho raiz do disco const code = StringPrototypeCharCodeAt(path, 0); //o comprimento do caminho é 1 if (len === 1) { // Existe apenas um separador de caminho para caminho absoluto if (isPathSeparator(code)) { rootEnd = 1; éAbsoluto = verdadeiro; } } else if (isPathSeparator(código)) { // Pode ser uma raiz UNC, começando com um delimitador , pelo menos um dos quais é algum tipo de caminho absoluto (UNC ou outro) éAbsoluto = verdadeiro; // Começa a combinar o separador de caminho duplo if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { seja j = 2; deixe por último = j; // Corresponde a um ou mais delimitadores que não sejam de caminho while (j < len && !isPathSeparator(StringPrototypeCharCodeAt(caminho, j))) { j++; } if (j < len && j !== último) { const primeiraPart = StringPrototypeSlice(caminho, último, j); último = j; // Corresponde a um ou mais separadores de caminho while (j < len && isPathSeparator(StringPrototypeCharCodeAt(caminho, j))) { j++; } if (j < len && j !== último) { último = j; while (j <len && !isPathSeparator(StringPrototypeCharCodeAt(caminho, j))) { j++; } if (j === len || j !== último) { dispositivo = `\\${firstPart}\${StringPrototypeSlice(caminho, último, j)}`; rootEnd = j; } } } } outro { rootEnd = 1; } // Detecta exemplo de correspondência do diretório raiz do disco: D:, C: } else if (isWindowsDeviceRoot(código) && StringPrototypeCharCodeAt(caminho, 1) === CHAR_COLON) { dispositivo = StringPrototypeSlice(caminho, 0, 2); rootEnd = 2; if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(caminho, 2))) { éAbsoluto = verdadeiro; rootEnd = 3; } }
Detecte o caminho e gere-o, verifique se o diretório raiz do disco existe ou resolva se resolvedAbsolute
é um caminho absoluto.
//Detecta o diretório raiz do disco if (device.length > 0) { // resolveDevice tem valor if (resolvedDevice.length > 0) { if (StringPrototypeToLowerCase(dispositivo)!== StringPrototypeToLowerCase(resolvidoDevice)) continuar; } outro { // resolveDevice não tem valor e recebe o valor do diretório raiz do disco resolviDevice = device; } } // Caminho absoluto if (resolvedAbsolute) { //Há um loop final se o diretório raiz do disco existir (resolvedDevice.length > 0) quebrar; } outro { // Obtém o prefixo do caminho para emendar resolveTail = `${StringPrototypeSlice(caminho, rootEnd)}\${resolvedTail}`; resolvidoAbsoluto = éAbsoluto; if (isAbsolute && resolveDevice.length > 0) { // O loop termina quando a raiz do disco existe break; } }
join executa a emenda do caminho com base nos fragmentos do caminho de entrada
Receba vários parâmetros, use separadores específicos como delimitadores para conectar todos os parâmetros do caminho e gere um novo caminho normalizado.
Depois de receber os parâmetros, verifique-os. Se não houver parâmetros, ele retornará '.' Caso contrário, ele percorrerá e verificará cada parâmetro por meio do método validateString
integrado. Se houver alguma violação, throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
join
função do caractere de escape é que quando usado sozinho, ele é considerado um escape da string após a barra, portanto, barras invertidas duplas são usadas para escapar da barra invertida ('').
Finalmente, a string concatenada é verificada e retornada em formato.
if (args. comprimento === 0) retornar '.'; deixe-se juntar; deixe firstPart; // Detecta parâmetros da esquerda para a direita for (let i = 0; i < args.length; ++i) { const arg = args[i]; // interno/validadores validarString(arg, 'caminho'); if (comprimento do argumento > 0) { if (ingressou === indefinido) // Atribua a primeira string à junção e use a variável firstPart para salvar a primeira string para uso posterior join = firstPart = arg; outro // unido tem um valor, execute += operação de emenda unido += `\${arg}`; } } if (ingressou === indefinido) return '.';
No sistema de janelas, o processamento do caminho de rede é necessário devido ao uso de barra invertida ('') e UNC (referindo-se principalmente ao nome completo dos recursos do Windows 2000 na LAN), ('') representa é um formato de caminho de rede, portanto, o método join
montado no win32 interceptará por padrão.
Se uma barra invertida ('') for correspondida, slashCount
será incrementado Enquanto houver mais de duas barras invertidas ('') correspondentes, o caminho emendado será interceptado e emendado e escapado manualmente (. '').
deixe necessidadesReplace = true; deixe barraCount = 0; // Extraia o código da primeira string em sequência de acordo com StringPrototypeCharCodeAt e combine-o com o código definido por meio do método isPathSeparator if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) { ++Contagem de barras; const firstLen = firstPart.length; if (firstLen > 1 && isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) { ++Contagem de barras; if (firstLen > 2) { if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2))) ++Contagem de barras; outro { precisaReplace = falso; } } } } if (precisa substituir) { while (slashCount <unido.comprimento && isPathSeparator(StringPrototypeCharCodeAt(juntado, slashCount))) { barraContagem++; } if (contagem de barras >= 2) unido = `\${StringPrototypeSlice(juntado, slashCount)}`; }
Classificação dos resultados da execução
resolve | join | |
---|---|---|
não tem parâmetros | . | O caminho absoluto do arquivo atual |
absoluto | ||
do | arquivo atual é dividido | em ordem. |
dividido no caminho absoluto dos | caminhos não absolutos subsequentes. | O|
pós-parâmetro do caminho é um | parâmetro de caminho absoluto. O caminho substitui o caminho absoluto do arquivo atual e substitui | o caminho emendado pelo. | pré-parâmetros
O primeiro parâmetro é (./) | e possui parâmetros subsequentes. O parâmetro de emenda do caminho absoluto do arquivo atual não possui parâmetros subsequentes | . pelos parâmetros subseqüentes não possui parâmetros subseqüentes (./) |
pós | ||
-parâmetro possui (./) | O parâmetro de emenda do caminho absoluto analisado | possui parâmetros subseqüentes. |
o primeiro parâmetro é (../) | e há parâmetros subsequentes. Os parâmetros de emenda após o último diretório de nível que cobre o caminho absoluto do arquivo atual não possuem parâmetros subsequentes | . . Splicing Não há parâmetros subseqüentes para parâmetros subseqüentes (../) |
O pós-parâmetro possui (../ | )O diretório de nível superior onde (../) aparece será substituído. substituído. O diretório de nível superior será sobrescrito. Após retornar (/), os parâmetros subsequentes serão emendados e | o diretório superior que aparece (../) será sobrescrito Quantas camadas aparecem no sufixo. Após a substituição do diretório superior, o |
lido. Após o código-fonte, o método resolve
processará os parâmetros, considerará a forma do caminho e descartará o caminho absoluto no final. Ao usá-lo, se você estiver realizando operações como arquivos, é recomendado usar o método resolve
. Em comparação, o método resolve
retornará um caminho mesmo que não haja parâmetros para o usuário operar, e o caminho será processado. durante o processo de execução. O método join
realiza apenas a emenda padronizada dos parâmetros recebidos, o que é mais prático para gerar um novo caminho e pode ser criado de acordo com a vontade do usuário. No entanto, cada método tem suas vantagens. Você deve escolher o método apropriado de acordo com seus próprios cenários de uso e necessidades do projeto.