
ในระหว่างกระบวนการพัฒนา มักจะใช้ Node.js ซึ่งใช้ความสามารถที่ได้รับจาก V8 เพื่อขยายขีดความสามารถของ JS ใน Node.js เราสามารถใช้โมดูลเส้นทางที่ไม่มีอยู่ใน JS เพื่อให้เราคุ้นเคยกับแอปพลิเคชันมากขึ้น เรามาดูกันดีกว่า~
เวอร์ชัน Node.js ของบทความนี้คือ 16.14.0 และซอร์สโค้ดของบทความนี้มาจากที่นี่ Version ฉันหวังว่าหลังจากอ่านบทความนี้แล้ว จะเป็นประโยชน์สำหรับทุกคนในการอ่านซอร์สโค้ด
ใช้ในการประมวลผลเส้นทางของไฟล์และไดเร็กทอรี โมดูลนี้มีฟังก์ชันเครื่องมือบางอย่างที่สะดวกสำหรับนักพัฒนาในการพัฒนา เพื่อช่วยเราในการตัดสินเส้นทางที่ซับซ้อนและปรับปรุงประสิทธิภาพการพัฒนา ตัวอย่างเช่น:
กำหนดค่านามแฝงในโครงการ การกำหนดค่านามแฝงช่วยให้เราอ้างอิงไฟล์ได้ง่ายขึ้นและหลีกเลี่ยงการค้นหาขึ้นไปทีละขั้นตอน
รักอีกครั้ง: {
นามแฝง: {
// __dirname เส้นทางไดเรกทอรี 'src' โดยที่ไฟล์ปัจจุบันตั้งอยู่: path.resolve(__dirname, './src'),
// process.cwd ไดเร็กทอรีการทำงานปัจจุบัน '@': path.join(process.cwd(), 'src'),
-
} ใน webpack สามารถสร้างเส้นทางเอาต์พุตของไฟล์ไปยังตำแหน่งที่ระบุผ่านการกำหนดค่าของเราเอง
โมดูล.ส่งออก = {
รายการ: './path/to/my/entry/file.js',
เอาท์พุท: {
เส้นทาง: path.resolve(__dirname, 'dist'),
ชื่อไฟล์: 'my-first-webpack.bundle.js',
-
}; หรือสำหรับการทำงานของโฟลเดอร์
ให้ fs = need("fs");
ให้ path = need("path");
// ลบโฟลเดอร์ ให้ deleDir = (src) => {
// อ่านโฟลเดอร์ให้เด็ก ๆ = fs.readdirSync(src);
เด็ก.forEach (รายการ => {
ให้ childpath = path.join(src, item);
// ตรวจสอบว่ามีไฟล์อยู่หรือไม่ ให้ file = fs.statSync(childpath).isFile();
ถ้า (ไฟล์) {
// ลบไฟล์หากมีอยู่ fs.unlinkSync(childpath)
} อื่น {
// ดำเนินการตรวจสอบโฟลเดอร์ deleDir (childpath) ต่อไป
-
-
// ลบโฟลเดอร์ว่าง fs.rmdirSync(src)
-
deleDir("../floor") เข้าใจสถานการณ์การใช้งานของพาธโดยสังเขป ต่อไป เราจะศึกษากลไกการดำเนินการและวิธีการนำไปใช้ตามการใช้งาน

เมื่อมีการแนะนำโมดูลพาธและเรียกใช้ฟังก์ชันเครื่องมือของพาธ ตรรกะการประมวลผลของโมดูลดั้งเดิมจะถูกป้อน
ใช้ฟังก์ชัน _load เพื่อใช้ชื่อโมดูลที่คุณแนะนำเป็น ID เพื่อพิจารณาว่าโมดูลที่จะโหลดนั้นเป็นโมดูล JS ดั้งเดิม หลังจากนั้น ฟังก์ชัน loadNativeModule จะถูกใช้เพื่อใช้ id เพื่อค้นหารหัส ASCII ที่เกี่ยวข้องจาก _source ( สตริงซอร์สโค้ดที่บันทึกโมดูล JS ดั้งเดิม) ข้อมูลจะถูกโหลดลงในโมดูล JS ดั้งเดิม
ดำเนินการไฟล์ lib/path.js และใช้กระบวนการเพื่อกำหนดระบบปฏิบัติการ อาจมีการประมวลผลที่แตกต่างกันของอักขระปฏิบัติการในการประมวลผลไฟล์ แต่วิธีการจะเหมือนกันโดยประมาณหลังจากประมวลผลแล้ว ผู้โทร
แก้ไขส่งกลับเส้นทางที่แน่นอนของเส้นทางปัจจุบัน
แก้ไขประกบพารามิเตอร์หลายตัวตามลำดับเพื่อสร้างเส้นทางที่แน่นอนใหม่
แก้ไข (... args) {
ให้แก้ไขอุปกรณ์ = '';
ให้ solvedTail = '';
ให้ SolvedAbsolute = false;
// ตรวจจับพารามิเตอร์จากขวาไปซ้ายสำหรับ (ให้ i = args.length - 1; i >= -1; i--) {
-
-
// เส้นทางที่ทำให้เป็นมาตรฐาน solvedTail = NormalizeString (resolvedTail, !resolvedAbsolute, '\', isPathSeparator);
กลับได้รับการแก้ไขแน่นอน?
`${resolvedDevice}\${resolvedTail}` :
`${resolvedDevice}${resolvedTail}` ||.';
- 
รับเส้นทางตามพารามิเตอร์ สำรวจพารามิเตอร์ที่ได้รับ เริ่มประกบเมื่อความยาวของพารามิเตอร์มากกว่าหรือเท่ากับ 0 ทำการตรวจสอบแบบไม่มีสตริงบนเส้นทางที่ประกบกัน หากมีพารามิเตอร์ใด ๆ ที่ไม่ตรงกัน throw new ERR_INVALID_ARG_TYPE(name, 'string', value) หากเป็นไปตามข้อกำหนด ความยาวของเส้นทางจะถูกตัดสิน หากมีค่า += path จะถูกนำมาใช้สำหรับขั้นตอนต่อไป
ให้เส้นทาง;
ถ้า (ผม >= 0) {
เส้นทาง = args[i];
// ภายใน/เครื่องมือตรวจสอบความถูกต้อง
validateString(เส้นทาง, 'เส้นทาง');
// หากความยาวของเส้นทางเป็น 0 มันจะกระโดดออกจากลูป for ของบล็อกโค้ดด้านบนโดยตรงถ้า (path.length === 0) {
ดำเนินการต่อ;
-
} อื่นถ้า (resolvedDevice.length === 0) {
//ความยาวของ SolvedDevice คือ 0 กำหนดค่าให้กับพาธเป็นไดเร็กทอรีการทำงานปัจจุบัน path = process.cwd();
} อื่น {
// กำหนดค่าให้กับวัตถุสภาพแวดล้อมหรือเส้นทางไดเร็กทอรีการทำงานปัจจุบัน = process.env[`=${resolvedDevice}`] || process.cwd();
ถ้า (เส้นทาง === ไม่ได้กำหนด ||
(StringPrototypeToLowerCase(StringPrototypeSlice(path, 0, 2)) !==
StringPrototypeToLowerCase (อุปกรณ์ที่แก้ไขแล้ว) &&
StringPrototypeCharCodeAt (เส้นทาง 2) === CHAR_BACKWARD_SLASH)) {
//ตัดสินเส้นทางไปยังเส้นทางที่ไม่ว่างเปล่าและเส้นทางสัมบูรณ์เพื่อให้ได้เส้นทาง path = `${resolvedDevice}\`;
-
- 
พยายามจับคู่พาธรูท ตรวจสอบว่ามีตัวคั่นพาธเพียงตัวเดียว ('') หรือพาธเป็นพาธสัมบูรณ์ จากนั้นทำเครื่องหมายพาธสัมบูรณ์และตั้งค่าแฟล็กการสกัดกั้น rootEnd เป็น 1 (ตัวห้อย) หากรายการที่สองยังคงเป็นตัวคั่นเส้นทาง ('') ให้กำหนดค่าการสกัดกั้นเป็น 2 (ตัวห้อย) และใช้ last เพื่อบันทึกค่าการสกัดกั้นสำหรับการตัดสินในภายหลัง
ดำเนินการต่อเพื่อตรวจสอบว่ารายการที่สามเป็นตัวคั่นเส้นทาง ('') หรือไม่ หากเป็นเช่นนั้น เป็นเส้นทางที่แน่นอน และตัวระบุการสกัดกั้น rootEnd คือ 1 (ตัวห้อย) แต่อาจเป็นเส้นทาง UNC (servernamesharename) , ชื่อเซิร์ฟเวอร์ ชื่อเซิร์ฟเวอร์) sharename ชื่อทรัพยากรที่ใช้ร่วมกัน) หากมีค่าอื่นๆ ค่าที่ดักจับจะยังคงเพิ่มขึ้นและอ่านค่าต่อไปนี้ และใช้ firstPart เพื่อบันทึกค่าของบิตที่สามเพื่อให้สามารถรับค่าได้เมื่อประกบไดเร็กทอรี และเก็บค่าสุดท้ายและค่าที่ดักไว้ สม่ำเสมอในการยุติคำพิพากษา
const len = path.length;
ให้ rootEnd = 0; // ตัวห้อยสิ้นสุดการสกัดกั้นเส้นทาง ให้อุปกรณ์ = ''; // ดิสก์รูท D:, C:
ให้ isAbsolute = false; // ไม่ว่าจะเป็นเส้นทางรากของดิสก์ const code = StringPrototypeCharCodeAt (เส้นทาง, 0);
// ความยาวเส้นทางคือ 1
ถ้า (เลน === 1) {
// มีตัวคั่นพาธเพียงตัวเดียวเท่านั้น สำหรับพาธสัมบูรณ์ถ้า (isPathSeparator(code)) {
รากสิ้นสุด = 1;
เป็นสัมบูรณ์ = จริง;
-
} อื่นถ้า (isPathSeparator (รหัส)) {
// อาจเป็นรากของ UNC โดยเริ่มต้นด้วยตัวคั่น อย่างน้อยหนึ่งในนั้นเป็นเส้นทางที่แน่นอน (UNC หรืออื่น ๆ )
เป็นสัมบูรณ์ = จริง;
// เริ่มจับคู่ตัวคั่นเส้นทางคู่ถ้า (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
ให้เจ = 2;
ให้สุดท้าย = j;
// จับคู่ตัวคั่นที่ไม่ใช่เส้นทางตั้งแต่หนึ่งตัวขึ้นไปในขณะที่ (j < len &&
!isPathSeparator(StringPrototypeCharCodeAt(เส้นทาง, j))) {
เจ++;
-
ถ้า (j < len && j !== สุดท้าย) {
const firstPart = StringPrototypeSlice (เส้นทาง, สุดท้าย, j);
สุดท้าย = เจ;
// จับคู่ตัวคั่นเส้นทางตั้งแต่หนึ่งตัวขึ้นไปในขณะที่ (j < len &&
isPathSeparator (StringPrototypeCharCodeAt (เส้นทาง, j))) {
เจ++;
-
ถ้า (j < len && j !== สุดท้าย) {
สุดท้าย = เจ;
ในขณะที่ (j <เลน &&
!isPathSeparator(StringPrototypeCharCodeAt(เส้นทาง, j))) {
เจ++;
-
ถ้า (j === len || j !== สุดท้าย) {
อุปกรณ์=
`\\${ส่วนแรก}\${StringPrototypeSlice(เส้นทาง, สุดท้าย, j)}`;
rootEnd = เจ;
-
-
-
} อื่น {
รากสิ้นสุด = 1;
-
// ตรวจหาไดเร็กทอรีรากของดิสก์ตัวอย่างที่ตรงกัน: D:, C:
} อื่นถ้า (isWindowsDeviceRoot (รหัส) && StringPrototypeCharCodeAt (เส้นทาง 1) === CHAR_COLON) {
อุปกรณ์ = StringPrototypeSlice (เส้นทาง, 0, 2);
รากสิ้นสุด = 2;
ถ้า (len > 2 && isPathSeparator (StringPrototypeCharCodeAt (เส้นทาง 2))) {
เป็นสัมบูรณ์ = จริง;
รากสิ้นสุด = 3;
-
} ตรวจหาเส้นทางและสร้าง ตรวจสอบว่ามีไดเร็กทอรีรากของดิสก์อยู่หรือแก้ไขว่า resolvedAbsolute เป็นเส้นทางที่แน่นอนหรือไม่
// ตรวจหาไดเรกทอรีรากของดิสก์ถ้า (device.length > 0) {
// solvedDevice มีค่าถ้า (resolvedDevice.length > 0) {
ถ้า (StringPrototypeToLowerCase (อุปกรณ์) !==
StringPrototypeToLowerCase (อุปกรณ์ที่แก้ไขแล้ว))
ดำเนินการต่อ;
} อื่น {
// solvedDevice ไม่มีค่าและได้รับการกำหนดค่าของไดเร็กทอรีรากของดิสก์ solvedDevice = อุปกรณ์;
-
-
// เส้นทางที่แน่นอนถ้า (แก้ไขแล้วแน่นอน) {
// มีการวนรอบสุดท้ายหากมีไดเรกทอรีรากของดิสก์อยู่ (resolvedDevice.length > 0)
หยุดพัก;
} อื่น {
// รับคำนำหน้าเส้นทางสำหรับการประกบ solvedTail =
`${StringPrototypeSlice(path, rootEnd)}\${resolvedTail}`;
ได้รับการแก้ไขแน่นอน = isAbsolute;
ถ้า (isAbsolute && แก้ไขอุปกรณ์ความยาว > 0) {
// การวนซ้ำจะสิ้นสุดลงเมื่อรูทของดิสก์เสียหาย
-
} เข้าร่วมดำเนินการประกบเส้นทางตามส่วนของเส้นทางที่เข้ามา

รับพารามิเตอร์หลายตัว ใช้ตัวแยกเฉพาะเป็นตัวคั่นเพื่อเชื่อมต่อพารามิเตอร์เส้นทางทั้งหมดเข้าด้วยกัน และสร้างเส้นทางมาตรฐานใหม่
หลังจากได้รับพารามิเตอร์ throw new ERR_INVALID_ARG_TYPE(name, 'string', value); ให้ตรวจสอบ หากไม่มีพารามิเตอร์ จะส่งกลับ validateString .' โดยตรง throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
join ของอักขระ Escape คือเมื่อใช้เพียงอย่างเดียว จะถือว่า Escape สตริงหลังเครื่องหมายทับ ดังนั้นจึงใช้เครื่องหมายแบ็กสแลชคู่เพื่อยกเว้นเครื่องหมายแบ็กสแลช ('')
ในที่สุด สตริงที่ต่อกันจะได้รับการตรวจสอบและส่งคืนในรูปแบบ
ถ้า (หาเรื่องความยาว === 0)
กลับ '.';
มาร่วม;
ให้ก่อนส่วน;
// ตรวจจับพารามิเตอร์จากซ้ายไปขวาสำหรับ (ให้ i = 0; i < args.length; ++i) {
const หาเรื่อง = หาเรื่อง [i];
// ภายใน/เครื่องมือตรวจสอบความถูกต้อง
validateString(arg, 'เส้นทาง');
ถ้า (ความยาวหาเรื่อง > 0) {
ถ้า (เข้าร่วม === ไม่ได้กำหนด)
// กำหนดสตริงแรกที่จะเข้าร่วม และใช้ตัวแปร firstPart เพื่อบันทึกสตริงแรกเพื่อใช้ในภายหลัง join = firstPart = arg;
อื่น
// เข้าร่วมมีค่าดำเนินการ += การดำเนินการประกบเข้าร่วม += `\${arg}`;
-
-
ถ้า (เข้าร่วม === ไม่ได้กำหนด)
return '.'; ภายใต้ระบบหน้าต่าง จำเป็นต้องมีการประมวลผลเส้นทางเครือข่ายเนื่องจากการใช้แบ็กสแลช ('') และ UNC (ส่วนใหญ่อ้างอิงถึงชื่อทรัพยากร Windows 2000 ที่สมบูรณ์บนเส้นทาง LAN) ('') แสดงถึงรูปแบบเส้นทางเครือข่าย ดังนั้นวิธี join ที่ติดตั้งภายใต้ win32 จะถูกดักจับตามค่าเริ่มต้น
หากจับคู่แบ็กสแลช ('') slashCount จะเพิ่มขึ้น ตราบใดที่มีแบ็กสแลชมากกว่าสองอัน ('') ที่ตรงกัน เส้นทางที่ประกบกันจะถูกดักและประกบกันด้วยตนเองและหลบหนี ( '')
ให้ needReplace = จริง;
ให้ slashCount = 0;
// แยกโค้ดโค้ดของสตริงแรกตามลำดับตาม StringPrototypeCharCodeAt และจับคู่กับโค้ดโค้ดที่กำหนดผ่านเมธอด isPathSeparator if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) {
++สแลชนับ;
const firstLen = firstPart.length;
ถ้า (firstLen > 1 &&
isPathSeparator (StringPrototypeCharCodeAt (ส่วนแรก, 1))) {
++สแลชนับ;
ถ้า (firstLen > 2) {
ถ้า (isPathSeparator (StringPrototypeCharCodeAt (FirstPart, 2)))
++สแลชนับ;
อื่น {
needReplace = เท็จ;
-
-
-
-
ถ้า (ต้องการแทนที่) {
ในขณะที่ (slashCount < join.length &&
isPathSeparator (StringPrototypeCharCodeAt (เข้าร่วม, slashCount))) {
slashCount++;
-
ถ้า (slashCount >= 2)
เข้าร่วม = `\${StringPrototypeSlice(เข้าร่วม, slashCount)}`;
} การเรียงลำดับผลลัพธ์การดำเนินการ
| การแก้ไขการ | รวม | |
|---|---|---|
| ไม่มีพารามิเตอร์ | เส้นทาง | ที่แน่นอนของไฟล์ปัจจุบัน |
| พารามิเตอร์ไม่มี | เส้นทางที่แน่นอนของไฟล์ปัจจุบันถูกเชื่อม | ต่อตาม |
| ลำดับ | ของไฟล์ปัจจุบันและถูกต่อเข้ากับพาธสัมบูรณ์ของ | พาธที่ไม่แน่นอนที่ตามมา | พา
| ธ | จะเขียนทับพาธสัมบูรณ์ของไฟล์ปัจจุบันและเขียนทับ | พาธที่ประกบกันด้วย | พารามิเตอร์ล่วงหน้า
| พารามิเตอร์แรกคือ (./) | และมีพารามิเตอร์ที่ตามมา พารามิเตอร์ splicing เส้นทางสัมบูรณ์ของไฟล์ปัจจุบันไม่มีพารามิเตอร์ที่ตาม | มา โดยพารามิเตอร์ที่ตามมาไม่มีพารามิเตอร์ที่ตามมา (./) |
| พารามิเตอร์หลังมี (./) | พารามิเตอร์การแยกวิเคราะห์เส้นทางสัมบูรณ์ | มีพารามิเตอร์ที่ตามมาไม่มีพารามิเตอร์ที่ตามมาและการประกบกัน (/ |
| ) พารามิเตอร์แรกคือ (../) | และมีพารามิเตอร์ที่ตามมา พารามิเตอร์ splicing หลังจากไดเร็กทอรีระดับสุดท้ายที่ครอบคลุมเส้นทางสัมบูรณ์ของไฟล์ปัจจุบันไม่มีพารามิเตอร์ที่ตาม | มา การเชื่อมต่อ ไม่มีพารามิเตอร์ที่ตามมาสำหรับพารามิเตอร์ที่ตามมา (../) |
| พารามิเตอร์หลังมี (../ | )ไดเรกทอรีระดับบนที่ (../) ปรากฏจะถูกเขียนทับ เขียนทับ ไดเร็กทอรีระดับบนจะถูกเขียนทับ หลังจากนั้น ให้ส่งคืน (/) พารามิเตอร์ที่ตามมาจะถูกเชื่อมต่อและ | ไดเร็กทอรีด้านบนที่ปรากฏ (../) จะถูกเขียนทับจำนวนเลเยอร์ที่ปรากฏในส่วนต่อท้าย หลังจากที่ไดเร็กทอรีด้านบนถูกเขียนทับ |
ถูกอ่าน หลังจากซอร์สโค้ด วิธี resolve จะประมวลผลพารามิเตอร์ พิจารณารูปแบบของเส้นทาง และโยนเส้นทางสัมบูรณ์ออกไปที่ส่วนท้าย เมื่อใช้งาน หากคุณกำลังดำเนินการต่างๆ เช่น ไฟล์ ขอแนะนำให้ใช้วิธี resolve ในการเปรียบเทียบ วิธี resolve จะส่งคืนเส้นทางแม้ว่าจะไม่มีพารามิเตอร์ให้ผู้ใช้ดำเนินการก็ตาม และเส้นทางจะถูกประมวลผล ในระหว่างกระบวนการดำเนินการ วิธี join จะดำเนินการประกบพารามิเตอร์ขาเข้าที่เป็นมาตรฐานเท่านั้น ซึ่งมีประโยชน์มากกว่าสำหรับการสร้างเส้นทางใหม่และสามารถสร้างได้ตามความต้องการของผู้ใช้ อย่างไรก็ตาม แต่ละวิธีมีข้อดีของตัวเอง คุณควรเลือกวิธีที่เหมาะสมตามสถานการณ์การใช้งานและความต้องการของโครงการ