1. التحليل الافتتاحي
في الفصل السابق ، تعلمنا المعرفة النظرية الأساسية من Nodejs. فهم هذه المعرفة النظرية أمر بالغ الأهمية. في الفصول اللاحقة ، سنتعلم تدريجياً الوحدات المختلفة في الوثائق الرسمية. حسنًا ، لقد حان الوقت لظهور بطل هذه المقالة على المسرح. عالمي
لنلقي نظرة على التعريف الرسمي:
الكائنات العالمية هذه الكائنات متوفرة في جميع الوحدات النمطية. بعض هذه الكائنات ليست في النطاق العالمي ولكن في نطاق الوحدة - سيتم ملاحظة ذلك.
هذه الكائنات متوفرة في جميع الوحدات النمطية. في الواقع ، فإن بعض الأشياء ليست في نطاق النطاق العالمي ، ولكن في نطاق الوحدة النمطية - سيتم تحديدها.
في المتصفحات ، النطاق العالي هو النطاق العالمي. هذا يعني أنه في المتصفحات إذا كنت في النطاق العالمي var something سيحدد متغيرًا عالميًا.
في العقدة هذا مختلف. النطاق الأعلى ليس هو النطاق العالمي ؛ var something داخل وحدة العقدة سيكون محليًا لتلك الوحدة النمطية.
أعتقد أنه لا ينبغي أن يكون الجميع على دراية بمفهوم الكائنات العالمية. في المتصفح ، فإن أعلى مستوى هو النطاق العالمي ، مما يعني أنه إذا كنت تستخدم "VAR" لتحديد متغير في النطاق العالمي ، فسيتم تعريف هذا المتغير على أنه نطاق عالمي.
لكنه يختلف في nodejs. أعلى مستوى من النطاق ليس النطاق العالمي. في وحدة نمطية ، يتم تعريف المتغير باستخدام "var" وهذا المتغير هو فقط في نطاق هذه الوحدة.
في Nodejs ، تتوفر المتغيرات أو الوظائف أو الأساليب المحددة في الوحدة النمطية فقط في تلك الوحدة ، ولكن يمكن تمريرها إلى خارج الوحدة من خلال استخدام كائن الصادرات.
ومع ذلك ، في Node.js ، لا يزال هناك نطاق عالمي ، أي يمكنك تحديد المتغيرات أو الوظائف أو الفئات التي لا تتطلب تحميل أي وحدات.
في الوقت نفسه ، يتم تعريف بعض الأساليب العالمية والكائنات العالمية العالمية للطبقة العالمية مسبقًا ، وهي مساحات الأسماء العالمية في NodeJS. أي متغيرات أو وظائف أو كائنات عالمية هي قيم سمة للكائن.
في بيئة تشغيل الاستبدال ، يمكنك مراقبة التفاصيل في الكائن العالمي من خلال البيان التالي ، راجع الشكل أدناه:
سأتحدث عن كائنات قيمة السمة ذات الصلة المثبتة على الكائن العالمي واحدًا تلو الآخر أدناه.
(1) ، العملية
Process {Object} كائن Process. انظر قسم كائن العملية.
العملية {Object} هذا كائن عملية. سأشرح بالتفصيل في الفصول اللاحقة ، لكن هنا سأخرج أولاً واجهة برمجة التطبيقات للحديث عنها.
Process.NextTick (رد الاتصال)
في الحلقة التالية حول حلقة الحدث ، اتصل بهذا الاتصال. هذا ليس مستعارًا بسيطًا لـ SetTimeout (FN ، 0) ، إنه أكثر كفاءة. يتم تشغيله عادة قبل أي أحداث I/O أخرى ، ولكن هناك بعض الاستثناءات. انظر Process.MaxTickDepth أدناه.
وظيفة رد الاتصال في الحلقة التالية من حلقة الحدث. هذا ليس مستعارًا بسيطًا لوظيفة SetTimeout (FN ، 0) ، لأنها أكثر كفاءة.
يمكن لهذه الوظيفة استدعاء وظيفة رد الاتصال لدينا قبل أي I/O. إذا كنت ترغب في إجراء عمليات معينة بعد إنشاء الكائن وقبل حدوث عملية I/O ، فإن هذه الوظيفة مهمة جدًا بالنسبة لك.
كثير من الناس لا يفهمون استخدام Process.NextTick () في Node.js. دعونا نلقي نظرة على ما هو العملية. nexttick () وكيفية استخدامها.
Node.js هو واحد الخيال. باستثناء النظام IO ، سيتم معالجة حدث واحد فقط في نفس الوقت أثناء عملية الاقتراع الحدث. يمكنك التفكير في استطلاع الأحداث كقائمة انتظار كبيرة ، في كل نقطة زمنية ، سيقوم النظام بمعالجة حدث واحد فقط.
حتى إذا كان جهاز الكمبيوتر الخاص بك يحتوي على نوى متعددة وحدة المعالجة المركزية ، فلا يمكنك التعامل مع أحداث متعددة بالتوازي في نفس الوقت. ولكن هذه الميزة تجعل Node.js مناسبة لمعالجة تطبيقات الإدخال/الإخراج ، ولكن ليس لتطبيقات حوسبة وحدة المعالجة المركزية.
في كل تطبيق I/O ، تحتاج فقط إلى تحديد وظيفة رد الاتصال لكل إدخال وإخراج ، وسيتم إضافتها تلقائيًا إلى قائمة انتظار معالجة الاقتراع.
عند اكتمال عملية الإدخال/الإخراج ، سيتم تشغيل وظيفة رد الاتصال هذه. سيستمر النظام بعد ذلك في معالجة الطلبات الأخرى.
في وضع المعالجة هذا ، تعني Process.NextTick () تحديد إجراء ما ودع هذا الإجراء يتم تنفيذه في الوقت المناسب عندما تكون استطلاعات الحدث التالي. دعونا نلقي نظرة على مثال. في المثال ، هناك foo () التي تريد الاتصال بها في الوقت التالي ، يمكنك القيام بذلك:
نسخة الكود كما يلي:
وظيفة foo () {
console.error ('foo') ؛
}
Process.NextTick (FOO) ؛
console.error ('bar') ؛
قم بتشغيل الرمز أعلاه وسترى أن إخراج "BAR" أمام "Foo". هذا يتحقق من البيان أعلاه الذي يعمل FOO () في المرحلة التالية من الوقت.
نسخة الكود كما يلي:
حاجِز
فو
يمكنك أيضًا استخدام وظيفة setTimeOut () لتحقيق نفس تأثير التنفيذ:
نسخة الكود كما يلي:
setTimeout (foo ، 0) ؛
console.log ('bar') ؛
ومع ذلك ، من حيث آلية المعالجة الداخلية ، تختلف Process.nextTick () و SetTimeout (FN ، 0). Process.NextTick () ليس تأخيرًا بسيطًا ، فهو يحتوي على المزيد من الميزات.
بتعبير أدق ، فإن المكالمة المحددة بواسطة Process.NextTick () تنشئ بديلاً جديدًا. في المكدس الحالي ، يمكنك إجراء العديد من العمليات كما تريد. ولكن بمجرد استدعاء Netxtick ، يجب إرجاع الوظيفة إلى المكدس الأصل. ثم تنتظر آلية الاقتراع في الحدث أحداثًا جديدة تتم معالجتها مرة أخرى. إذا تم العثور على NextTick ، سيتم إنشاء مكدس جديد.
دعونا نلقي نظرة على الظروف لاستخدام Process.nextTick ():
مهام عمل مكثفة للتشغيل في مجال وحدة المعالجة المركزية في أحداث متعددة:
في المثال التالي ، هناك حساب (). نأمل أن يتم تنفيذ هذه الوظيفة بشكل مستمر قدر الإمكان لأداء بعض المهام كثيفة العمليات.
ولكن في الوقت نفسه ، نأمل أيضًا ألا يتم حظر النظام من خلال هذه الوظيفة وسيكون قادرًا أيضًا على الاستجابة والتعامل مع الأحداث الأخرى. يشبه نمط التطبيق هذا خادم خدمة ويب مترابط واحد. هنا يمكننا استخدام Process.NextTick () لتبادل الحساب () واستجابة الحدث العادي.
نسخة الكود كما يلي:
var http = require ('http') ؛
وظيفة compute () {
// يقوم بحسابات معقدة بشكل مستمر
// ...
Process.NextTick (حساب) ؛
}
http.createserver (وظيفة (req ، الدقة) {
Res.Writehead (200 ، {'content-type': 'text/plain'}) ؛
res.end ('Hello World') ؛
}). الاستماع (5000 ، '127.0.0.1') ؛
حساب () ؛
في هذا الوضع ، لا نحتاج إلى استدعاء compute () بشكل متكرر. نحتاج فقط إلى استخدام Process.nextTick () لتحديد compute () للتنفيذ في النقطة التالية في حلقة الحدث.
خلال هذه العملية ، إذا جاء طلب HTTP جديد ، فستقوم آلية حلقة الحدث أولاً بمعالجة الطلب الجديد ثم استدعاء COMPUTE ().
على العكس من ذلك ، إذا وضعت compute () في مكالمة عودية ، فسيتم حظر النظام في Compute () ولا يمكنه معالجة طلبات HTTP الجديدة. يمكنك تجربة ذلك بنفسك.
بالطبع ، لا يمكننا الحصول على الفوائد الحقيقية للتنفيذ المتوازي تحت وحدات المعالجة المركزية المتعددة من خلال Process.nextTick () ، والتي هي فقط لمحاكاة نفس التطبيق الذي يتم تنفيذه في شرائح على وحدة المعالجة المركزية.
(2) ، وحدة التحكم
وحدة التحكم {Object} تستخدم للطباعة على stdout و stderr.see قسم stdio.
يتم استخدام Console {Object} لطباعة إلى الإخراج القياسي وإخراج الخطأ. انظر الاختبار التالي:
نسخة الكود كما يلي:
console.log ("Hello BigBear!") ؛
لـ (var i in console) {
console.log (i+""+console [i]) ؛
}
سيتم الحصول على نتائج الإخراج التالية:
نسخة الكود كما يلي:
var log = function () {
process.stdout.write (format.apply (هذا ، الوسائط) + '/n') ؛
}
var info = function () {
process.stdout.write (format.apply (هذا ، الوسائط) + '/n') ؛
}
var warn = function () {
WriteRror (format.apply (هذا ، الحجج) + '/n') ؛
}
var error = function () {
WriteRror (format.apply (هذا ، الحجج) + '/n') ؛
}
var dir = function (Object) {
var util = require ('Util') ؛
process.stdout.write (util.inspect (object) + '/n') ؛
}
var time = function (label) {
مرات [label] = date.now () ؛
}
var timeend = function (label) {
var المدة = date.now () - الأوقات [label] ؛
orports.log ('undefined: nanms' ، label ، المدة) ؛
}
var trace = function (label) {
// ربما يستطيع Toodo القيام بذلك بشكل أفضل مع كائن تصحيح V8 بمجرد ذلك
// مُعرض ل.
var err = خطأ جديد ؛
err.name = 'trace' ؛
err.message = label || '' ؛
error.capturestacktrace (err ، ediuments.callee) ؛
console.error (err.stack) ؛
}
var assert = function (expression) {
إذا (! التعبير) {
var arr = array.prototype.slice.call (الوسائط ، 1) ؛
تتطلب ('تأكيد'). ok (false ، format.apply (this ، arr)) ؛
}
}
من خلال هذه الوظائف ، نعرف بشكل أساسي ما الذي أضافته Nodejs إلى النطاق العالمي. في الواقع ، فإن واجهات برمجة التطبيقات ذات الصلة على كائن وحدة التحكم لا تتغلف إلا "stdout.write" على كائن العملية وتعليقها على الكائن العالمي.
(3) ، الصادرات والوحدة النمطية
في Nodejs ، هناك نطاقات ، مقسمة إلى نطاق عالمي ونطاق الوحدة النمطية
نسخة الكود كما يلي:
var name = 'var-name' ؛
name = 'name' ؛
global.name = 'global-name' ؛
this.name = 'module-name' ؛
console.log (global.name) ؛
console.log (this.name) ؛
console.log (الاسم) ؛
نرى أن var name = 'var-name' ؛ name = 'name' ؛ هو متغير محلي محدد.
global.name = 'global-name' ؛ يحدد سمة الاسم للكائن العالمي.
و this.name = 'module-name' ؛ يحدد سمة اسم كائن الوحدة النمطية
لذلك دعونا نتحقق من ذلك ، حفظ ما يلي على أنه Test2.js ، وقم بتشغيله
نسخة الكود كما يلي:
var t1 = require ('./ test1') ؛
console.log (t1.name) ؛
console.log (global.name) ؛
كما يتضح من النتائج ، قمنا باستيراد وحدة Test1 بنجاح وقمنا بتشغيل رمز Test1 لأن Global.Name هو الإخراج في Test2.
يتم تعريف T1.name في وحدة Test1 من خلال هذا. name ، مما يشير إلى أن هذا يشير إلى كائن نطاق الوحدة النمطية.
فرق بسيط بين الصادرات والوحدة النمطية
Module.exports هي الواجهة الحقيقية ، والصادرات هي مجرد أداة مساعدة لذلك. العودة النهائية إلى المكالمة هي Module.exports .
يتم تعيين جميع الخصائص والأساليب التي تم جمعها بواسطة الصادرات إلى Module.exports . بالطبع ، هناك شرط أساسي لهذا ، أي Module.exports本身不具备任何属性和方法。
如果, Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
خذ كستناء:
إنشاء ملف جديد bb.js
نسخة الكود كما يلي:
orports.name = function () {
console.log ("اسمي Big Bear!") ؛
} ؛
إنشاء اختبار ملف test.js
نسخة الكود كما يلي:
var bb = require ('./ bb.js') ؛
BB.Name () ؛ // 'اسمي Big Bear! '
تعديل BB.JS على النحو التالي:
نسخة الكود كما يلي:
module.exports = 'bigbear!' ؛
orports.name = function () {
console.log ("اسمي Big Bear!") ؛
} ؛
الرجوع إلى تنفيذ BB.JS مرة أخرى
نسخة الكود كما يلي:
var bb = require ('./ bb.js') ؛
BB.Name () ؛ // ليس له طريقة "اسم"
من هذا يمكننا أن نرى أن الوحدة النمطية الخاصة بك لا يتعين عليهم بالضرورة إرجاع "كائن محدد". يمكن أن تكون الوحدة النمطية أي كائن JavaScript قانوني -البوليان ، الرقم ، التاريخ ، JSON ، سلسلة ، وظيفة ، صفيف ، إلخ.
(4) ، setTimeout ، setInterval ، process.nexttick ، setImmediate
فيما يلي في شكل ملخص
يتميز NodeJS بالتزامن عالي الحدث الذي تم إنشاؤه بواسطة I/O غير المتزامن. المحرك الذي ينتج هذه الميزة هو حلقة حدث. يتم تصنيف الأحداث في مراقبي الأحداث المقابلة ، مثل المراقبين الخمول ، والمراقبين الموقت ، ومراقبي الإدخال/الإخراج ، وما إلى ذلك. تسمى كل حلقة من حلقة الحدث علامة. كل علامة تأخذ الأحداث من مراقبي الحدث بالتسلسل للمعالجة.
سيتم وضع المؤقت الذي تم إنشاؤه عند استدعاء setTimeOut () أو setInterval () في الشجرة الحمراء والأسود داخل مراقب المؤقت. في كل مرة تقوم فيها بالعلامة ، سيتحقق مما إذا كان المؤقت قد تجاوز وقت التوقيت من الشجرة الحمراء والأسود. إذا تجاوز التوقيت ، فسيتم تنفيذ وظيفة رد الاتصال المقابلة على الفور. تستخدم SetTimeOut () و setInterval () كلاهما من قبل أجهزة ضبط الوقت. الفرق هو أن الأخير يتم تشغيله مرارًا وتكرارًا ، ولأن إعداد الوقت قصير جدًا ، سيتم تشغيل المعالجة بعد المشغل السابق فور اكتمال المشغل السابق.
نظرًا لأن المؤقت هو مشغل مهلة ، فإن هذا سيقلل من دقة الزناد. على سبيل المثال ، يتم تعيين وقت المهلة مع setTimeout 5 ثوان. عندما تمر حلقة الحدث بمهمة في الثانية الرابعة ووقت التنفيذ الخاص بها هو 3 ثوانٍ ، ستنتهي وظيفة رد الاتصال SetTimeout لمدة ثانيتين ، وهذا هو سبب انخفاض الدقة. ولأن الموقت والحكم يتم حفظه باستخدام الأشجار الحمراء والأسود والأساليب التكرارية ، فهو مضيعة للأداء.
سيتم وضع جميع وظائف رد الاتصال باستخدام Process.NextTick () في المصفوفة ، وسيتم تنفيذها فورًا في المرة القادمة التي تقوم فيها بالعلامة. هذه العملية خفيفة الوزن ولديها دقة عالية.
يتم استدعاء وظيفة رد الاتصال التي تم تعيينها بواسطة SetImMediate () أيضًا على القراد التالي. الفرق بينه وبين Process.NextTick () هو نقطتان:
1. أولوية تنفيذ المراقب الذي ينتمون إليه مختلف. Process.NextTick () ينتمي إلى مراقب الخمول ، ينتمي SetImmediate () إلى مراقب الاختيار ، وولاية Idle> Check.
2. يتم وضع وظيفة رد الاتصال بواسطة SetImMediate () في قائمة مرتبطة ، ويتم تنفيذ رد اتصال واحد فقط في القائمة المرتبطة في كل مرة. هذا لضمان تنفيذ كل علامة بسرعة.
ثانياً ، دعنا نلخص
1. فهم معنى وجود الأشياء العالمية
2. فرق بسيط بين الصادرات والوحدة النمطية
3. ما هي الطبقة الأساسية من وحدة التحكم التي تم إنشاؤها (التغليف عالي المستوى لكائنات العملية)
4. الفرق بين setTimeout ، setInterval ، process.nexttick ، setImmediate
5. نطقان في Nodejs