قبل اقتراح مواصفات CommonJs، لم يكن لدى Javascript نظام وحدة نمطية، مما يعني أنه كان من الصعب علينا تطوير تطبيقات واسعة النطاق لأن تنظيم التعليمات البرمجية سيكون أكثر صعوبة.
بادئ ذي بدء، CommonJS ليس فريدًا بالنسبة إلى Node. CommonJS عبارة عن مواصفات وحدة تحدد كيفية الإشارة إلى الوحدات النمطية وتصديرها. تنقسم مواصفات وحدة CommonJS بشكل أساسي إلى ثلاثة أجزاء: مرجع الوحدة، وتعريف الوحدة، وتحديد الوحدة .
مرجع الوحدة
يعني مرجع الوحدة أنه يمكننا تقديم وحدات أخرى من خلال require
.
const { add } = require('./add'); نتيجة const = add(1,2);
تحدد الوحدة
الملف كوحدة نمطية، وستوفر الوحدة متغيرين، هما الوحدة النمطية والتصديرات. الوحدة هي الوحدة الحالية نفسها، والصادرات هي المحتوى الذي سيتم تصديره، والصادرات هي سمة من سمات الوحدة، أي أن الصادرات هي الوحدة النمطية.الصادرات. المحتوى الذي تستورده الوحدات الأخرى من خلال الطلب هو محتوى الوحدة النمطية.exports.
// add.js Exports.add = (أ، ب) => { العودة أ + ب؛ }
تعريف الوحدة
تعريف الوحدة هو المحتوى الموجود في require('./add')
على سبيل المثال، ثم تعريف الوحدة هو ./add
.
تتيح آلية استيراد وتصدير الوحدة التي تم إنشاؤها من خلال CommonJS للمستخدمين إنشاء تطبيقات واسعة النطاق بسهولة دون الحاجة إلى النظر في التلوث المتغير.
تنفيذ وحدة العقدة
تطبق Node مواصفات CommonJs وتضيف بعض الميزات التي تحتاجها. تقوم Node بشكل أساسي بالأمور الثلاثة التالية لتنفيذ مواصفات CommonJs:
تحديد موضع ملف
تحليل المسار
وتجميعه وتنفيذ
تحليل المسار
عند تنفيذ require()، تكون المعلمة المستلمة بواسطة require هي معرف الوحدة، وتقوم العقدة بإجراء تحليل المسار من خلال معرف الوحدة. الغرض من تحليل المسار هو العثور على المسار الذي توجد به هذه الوحدة من خلال معرف الوحدة. بادئ ذي بدء، يتم تقسيم وحدات العقدة إلى فئتين، وهما الوحدات الأساسية ووحدات الملفات. الوحدة الأساسية هي الوحدة التي تأتي مع العقدة، ووحدة الملف هي الوحدة التي كتبها المستخدم. في الوقت نفسه، يتم تقسيم وحدات الملفات إلى وحدات ملفات في شكل مسارات نسبية، ووحدات ملفات في شكل مسارات مطلقة، ووحدات ملفات في شكل غير مسارات (مثل Express).
عندما تعثر العقدة على وحدة ملف، فإنها ستقوم بتجميع الوحدة وتنفيذها وتخزينها مؤقتًا. المبدأ العام هو استخدام المسار الكامل للوحدة كمفتاح والمحتوى المترجم كقيمة، ولن تكون هناك حاجة لذلك عند تقديم الوحدة للمرة الثانية، قم بإجراء تحليل المسار وموقع الملف وتجميع وتنفيذ هذه الخطوات ويمكن قراءة المحتوى المترجم مباشرة من ذاكرة التخزين المؤقت.
// مخطط وحدة ذاكرة التخزين المؤقت: وحدة التخزين المؤقت الثابتة = { '/Usr/file/src/add.js': 'المحتوى المجمع لـ add.js', 'http': 'المحتوى المجمّع لوحدة http التي تأتي مع Node'، 'express': 'المحتوى المجمع لوحدة الملفات المخصصة غير المسارية السريعة' // ... }
عندما تريد العثور على الوحدة المستوردة حسب الطلب، فإن ترتيب البحث عن الوحدة هو التحقق أولاً مما إذا كانت الوحدة موجودة بالفعل في ذاكرة التخزين المؤقت، وإذا لم تكن موجودة في ذاكرة التخزين المؤقت، فتحقق من الوحدة الأساسية، ثم ابحث عنها وحدة الملف. من بينها، من السهل العثور على وحدات الملفات في شكل مسارات. يمكن الحصول على مسار الملف الكامل بناءً على المسار النسبي أو المطلق. من الصعب نسبيًا العثور على وحدات ملفات مخصصة في نموذج غير مسار. ستبحث Node عن الملف من المجلدNode_modules.
أين يوجد دليلNode_modules؟ على سبيل المثال، الملف الذي نقوم بتنفيذه حاليًا هو /Usr/file/index.js
؛ * /Usr/file/index.js؛ */ const { add } = require('add'); const result = add(1, 2);
في هذه الوحدة، قدمنا وحدة إضافة هذه الإضافة ليست وحدة أساسية ولا وحدة ملف في شكل مسار، فكيف يمكن العثور على وحدة الإضافة في هذا الوقت.
تحتوي الوحدة على سمة مسار. المسار للعثور على وحدة الإضافة موجود في سمة المسارات يمكننا كتابة هذه السمة لإلقاء نظرة:
/**. * /Usr/file/index.js; */ console.log(module.paths);
يمكننا طباعة قيمة المسارات عن طريق تنفيذ العقدة Index.js في دليل الملف. القيمة في المسارات عبارة عن مصفوفة، كما يلي:
[ "/Usr/file/node_modules"، '/Usr/node_modules'، "/node_modules"، ]
أي أن العقدة ستبحث بشكل تسلسلي من الدليل أعلاه لمعرفة ما إذا كانت تحتوي على وحدة الإضافة. المبدأ مشابه لسلسلة النموذج الأولي. أولاً، ابدأ البحث في المجلدNode_modules في الدليل بنفس مستوى الملف المنفذ حاليًا. إذا لم يتم العثور على الدليلNode_modules أو لم يكن موجودًا، فاستمر في البحث إلى المستوى الأعلى.
يتم استخدام تحليل مسارموقع الملف
وموقع الملف معًا، ويمكن أن يكون معرف الملف بدون لاحقة، أو يمكن العثور على دليل أو حزمة من خلال تحليل المسار.
تحليل امتداد الملف
const { add } = require('./add');
على سبيل المثال، في الكود أعلاه، لا يحتوي معرف الملف على امتداد. في هذا الوقت، ستبحث العقدة عن وجود .js، .json و .node بالتسلسل.
تحليل الدليل والحزمة
هو نفس الكود أعلاه، ما تم العثور عليه من خلال ./add
قد لا يكون ملفًا، ولكن قد يكون دليلاً أو حزمة (احكم على ما إذا كان دليلاً أو حزمة من خلال الحكم على ما إذا كانت هناك حزمة. json في مجلد الإضافة). في الوقت الحالي، خطوات تحديد موضع الملف هي كما يلي:
إذا لم يكن هناك حقل رئيسي في package.json، فسيتم استخدام الفهرس أيضًا كملف، ثم سيتم إجراء تحليل الامتداد للعثور على الملف باللاحقة المقابلة .
تجميع الوحدات
الوحدات الرئيسية التي نواجهها في التطوير هي وحدات json ووحدات js.
تجميع وحدة json
عندما نحتاج إلى وحدة json، ستساعدنا Node فعليًا في استخدام fs.readFilcSync لقراءة ملف json المقابل، والحصول على سلسلة json، ثم استدعاء JSON.parse للتحليل للحصول على كائن json، ثم تعيينه إلى الوحدة تصدر، ثم تعطيها للمطالبة.
تجميع وحدة js
عندما نحتاج إلى وحدة js، مثل
//index.js const { add } = require('./add');
// add.js Exports.add = (أ، ب) => { العودة أ + ب؛ }
ماذا حدث في هذا الوقت لماذا يمكننا استخدام وحدة المتغيرات والتصدير والطلب مباشرة في الوحدة؟ وذلك لأن Node تقوم بتغليف محتويات الوحدة أولاً وأخيراً عند تجميع وحدة js.
على سبيل المثال، سيتم تجميع وحدة add.js في بنية مشابهة لهذه عند تجميعها فعليًا:
(function(require, Exports, Module) { Exports.add = (أ، ب) => { العودة أ + ب؛ } إرجاع الوحدة النمطية.الصادرات؛ })(require, Module.exports, Module)
أي أن ملف js الذي نكتبه سيتم تجميعه في وظيفة. ما نكتبه هو فقط محتوى هذه الوظيفة، وعملية التعبئة اللاحقة للعقدة مخفية عنا. تدعم هذه الوظيفة تمرير بعض المعلمات، بما في ذلك الطلب والتصدير والوحدة النمطية.
بعد تجميع ملف js، سيتم تنفيذ الملف. ستقوم العقدة بتمرير المعلمات المقابلة لهذه الوظيفة ثم تنفيذها، وإرجاع قيمة الوحدة النمطية إلى الوظيفة المطلوبة.
ما ورد أعلاه هو العملية الأساسية لـ Node لتنفيذ مواصفات CommonJs.