في وحدات البرمجة التقليدية ، تشبه عمليات الإدخال/الإخراج استدعاء الوظيفة المحلية العادية: يتم حظر البرنامج قبل تنفيذ الوظيفة ولا يمكن الاستمرار في التشغيل. نشأت I/O المحظورة من نموذج شريحة الوقت السابق ، حيث تكون كل عملية مثل شخص مستقل ، بهدف تمييز الجميع ، وعادة ما يمكن للجميع فعل شيء واحد فقط في نفس الوقت ، ويجب أن ينتظروا القيام بالشيء السابق قبل تحديد ما يجب القيام به بعد ذلك. ومع ذلك ، فإن هذا النموذج من "مستخدم واحد ، عملية واحدة" تستخدم على نطاق واسع على شبكات الكمبيوتر والإنترنت قابلة للتطوير للغاية. عند إدارة عمليات متعددة ، فإنه يستهلك الكثير من الذاكرة والسياق أن يشغل أيضًا الكثير من الموارد. هذه عبء كبير على نظام التشغيل ، ومع زيادة عدد العمليات ، سوف يتحلل أداء النظام بشكل حاد.
Multithesply هو بديل. الخيط هو عملية خفيفة الوزن تشترك في الذاكرة مع مؤشرات ترابط أخرى في نفس العملية. يشبه امتداد النموذج التقليدي ، والذي يستخدم لتنفيذ مؤشرات ترابط متعددة بشكل متزامن. عندما ينتظر مؤشر ترابط واحد عمليات الإدخال/الإخراج ، يمكن لخيوط أخرى الاستيلاء على وحدة المعالجة المركزية. عند اكتمال عملية الإدخال/الإخراج ، سيتم إيقاظ الخيط الذي ينتظر في المقدمة. وهذا يعني ، يمكن مقاطعة الخيط الجاري ثم استئنافه لاحقًا. بالإضافة إلى ذلك ، يمكن أن تعمل المواضيع بالتوازي تحت نوى مختلفة من وحدات المعالجة المركزية متعددة النواة تحت بعض الأنظمة.
لا يعرف المبرمجون الوقت الذي سيتم فيه تشغيل الموضوع. يجب أن يكونوا حريصين على التعامل مع الوصول المتزامن إلى الذاكرة المشتركة ، لذلك يجب عليهم استخدام بعض بدائل التزامن لمزامنة الوصول إلى بنية بيانات معينة ، مثل استخدام الأقفال أو الإشارات ، لإجبار المواضيع على التنفيذ في سلوكيات وخطط محددة. يمكن للتطبيقات التي تعتمد بشكل كبير على الحالة المشتركة بين المواضيع أن تواجه بسهولة بعض المشكلات الغريبة مع العشوائية القوية وصعوبة في العثور عليها.
هناك طريقة أخرى تتمثل في استخدام تعاون متعدد الخيوط ، حيث تكون مسؤولاً عن إطلاق وحدة المعالجة المركزية بشكل صريح وتسليم وقت وحدة المعالجة المركزية للمواضيع الأخرى. نظرًا لأنك تتحكم شخصيًا في خطة تنفيذ مؤشر الترابط ، يتم تقليل الحاجة إلى التزامن ، ولكنها تزيد أيضًا من تعقيد البرنامج وفرصة الأخطاء ، ولا تتجنب مشاكل الرئاسة المتعددة.
ما هي البرمجة التي يحركها الحدث
البرمجة التي تعتمد على الحدث هي أسلوب برمجة ، حيث تحدد الأحداث عملية تنفيذ البرنامج. تتم معالجة الأحداث من قبل معالجات الأحداث أو عوائد الأحداث. عوائد الحدث هي وظائف تسمى عند حدوث حدث معين ، مثل قاعدة البيانات التي تُرجع نتيجة الاستعلام أو ينقر المستخدم على زر.
أذكر أنه في وضع برمجة الإدخال/الإخراج المحظور التقليدي ، قد تبدو استعلامات قاعدة البيانات هكذا:
نسخة الكود كما يلي:
النتيجة = استعلام ('حدد * من المنشورات حيث id = 1') ؛
do_something_with (النتيجة) ؛
ستقوم وظيفة الاستعلام أعلاه بإبقاء مؤشر الترابط الحالي أو العملية في حالة انتظار حتى تكمل قاعدة البيانات الأساسية عملية الاستعلام والإرجاع.
في النموذج الذي يحركه الحدث ، سيصبح هذا الاستعلام مثل هذا:
نسخة الكود كما يلي:
query_finished = function (النتيجة) {
do_something_with (النتيجة) ؛
}
الاستعلام ('حدد * من المنشورات حيث id = 1' ، query_finished) ؛
أولاً ، تقوم بتحديد وظيفة تسمى Query_Finished ، والتي تحتوي على ما يجب القيام به بعد اكتمال الاستعلام. ثم تمرير هذه الوظيفة كمعلمة إلى وظيفة الاستعلام. سيتم استدعاء Query_finished بعد تنفيذ الاستعلام ، بدلاً من مجرد إعادة نتيجة الاستعلام.
عندما يحدث حدث أنت مهتم به ، سيتم استدعاء الوظيفة التي تحددها بدلاً من مجرد إرجاع قيمة النتيجة. يسمى نموذج البرمجة برمجة تعتمد على الحدث أو البرمجة غير المتزامنة. هذا هو واحد من أكثر ميزات العقدة وضوحا. يعني نموذج البرمجة هذا أنه لن يتم حظر العملية الحالية عند تنفيذ عمليات الإدخال/الإخراج. لذلك ، يمكن تنفيذ عمليات الإدخال/الإخراج المتعددة بالتوازي ، وسيتم استدعاء وظيفة رد الاتصال المقابلة بعد اكتمال العملية.
تعتمد الطبقة الأساسية للبرمجة التي تعتمد على الحدث على حلقات الأحداث. تعد حلقات الأحداث هيكلًا في الأساس هيكلًا في الكشف عن الأحداث ومعالج الأحداث يؤدي إلى استدعاء الحلقة المستمرة لهاتين وظيفتين. في كل حلقة ، تحتاج آلية حلقة الحدث إلى اكتشاف الأحداث التي حدثت. عند حدوث الحدث ، يجد وظيفة رد الاتصال المقابلة ويطلق عليها.
حلقة الحدث هي مجرد موضوع يعمل في العملية. عند حدوث حدث ما ، يمكن أن يعمل معالج الأحداث بمفرده ولن يتم مقاطعة ، أي:
1. على الأكثر وظيفة رد اتصال حدث واحد في لحظة محددة
2. لا يتم مقاطعة معالج الأحداث عند الجري
مع هذا ، لم يعد بإمكان المطورين الصداع حول مزامنة الخيط والتعديل المتزامن للذاكرة المشتركة.
سر معروف:
منذ فترة طويلة ، كان الأشخاص في مجتمع برمجة النظام يعلمون أن البرمجة التي تعتمد على الحدث كانت أفضل طريقة لإنشاء خدمات توافق عالية لأنه لم يكن من الضروري توفير الكثير من السياق ، لذلك وفرت الكثير من الذاكرة ، وليس هذا القدر من التبديل السياق ، وحفظ الكثير من وقت التنفيذ.
ببطء ، تخلل هذا المفهوم المنصات والمجتمعات الأخرى ، وظهرت بعض تطبيقات حلقة الأحداث الشهيرة ، مثل آلة أحداث Ruby و Perl's Anyevnet و Python's Twisted. بالإضافة إلى هذه ، هناك العديد من التطبيقات واللغات الأخرى.
لتطوير هذه الأطر ، تحتاج إلى تعلم معرفة محددة تتعلق بالإطار والمكتبات الخاصة بالإطار. على سبيل المثال ، عند استخدام جهاز الحدث ، من أجل الاستمتاع بفوائد عدم الحظر ، يجب عليك تجنب استخدام مكتبات الفصول الدراسية المتزامنة ويمكنك استخدام مكتبات الفصول غير المتزامنة في آلة الحدث فقط. إذا كنت تستخدم أي مكتبة حظر (مثل معظم مكتبة Ruby القياسية) ، فإن الخادم الخاص بك يفقد قابلية التوسع الأمثل لأن حلقة الحدث ستظل محظورة باستمرار ، مما يمنع معالجة أحداث الإدخال/الإخراج من وقت لآخر.
تم تصميم العقدة في الأصل كمنصة خادم I/O غير المحظورة ، لذلك بشكل عام ، يجب أن تتوقع أن تكون كل الرمز الذي يتم تشغيله عليه غير محظور. نظرًا لأن JavaScript صغير جدًا ولا يجبر أي نموذج I/O (لأنه لا يحتوي على مكتبة فئة I/O قياسية) ، تم تصميم العقدة في بيئة نقية للغاية ولن تكون هناك مشكلات قديمة.
كيف تبسيط العقدة وجافا سكريبت التطبيقات غير المتزامنة
استخدم مؤلف Node Ryan Dahl في البداية C لتطوير هذا المشروع ، لكنه وجد أن سياق الحفاظ على مكالمات الوظائف كان معقدًا للغاية ، مما يؤدي إلى تعقيد الكود العالي. ثم تحول إلى لوا ، لكن لوا لديه بالفعل العديد من مكتبات الإدخال/الإخراج. قد يخلط خلط الحظر وغير الحظر للمطورين وبالتالي يمنع العديد من الأشخاص من بناء تطبيقات قابلة للتطوير. لذلك ، تم التخلي عن لوا من قبل دال. أخيرًا ، التفت إلى JavaScript ، الإغلاق في JavaScript ووظائف الكائنات من المستوى الأول ، مما يجعل JavaScript مناسبة للغاية للبرمجة التي تعتمد على الأحداث. يعد سحر JavaScript أحد الأسباب الرئيسية التي تجعل العقدة شائعة جدًا.
ما هو الإغلاق
يمكن فهم الإغلاق على أنه وظيفة خاصة ، ولكن يمكن أن يرث وتوصيل متغيرات الوصول في النطاق الذي يتم تعريفه. عندما تقوم بتمرير وظيفة رد الاتصال كمعلمة إلى وظيفة أخرى ، سيتم استدعاؤها لاحقًا. السحر هو أنه عندما يتم استدعاء وظيفة رد الاتصال هذه لاحقًا ، فإنها تتذكر في الواقع السياق الذي يحدد فيه نفسه والمتغيرات في سياق الأصل ، ويمكنه أيضًا الوصول إليها بشكل طبيعي. هذه الميزة القوية هي جوهر نجاح العقدة.
سيوضح المثال التالي كيف تعمل عمليات إغلاق JavaScript في متصفح الويب. إذا كنت ترغب في الاستماع إلى حدث مستقل على زر ، يمكنك القيام بذلك:
نسخة الكود كما يلي:
var clickCount = 0 ؛
document.getElementById ('mybutton'). onClick = function () {
ClickCount += 1 ؛
تنبيه ("نقر" + clickCount + "مرات.") ؛
} ؛
هكذا عند استخدام jQuery:
نسخة الكود كما يلي:
var clickCount = 0 ؛
$ ('button#mybutton'). انقر فوق (function () {
ClickedCount ++ ؛
ALERT ('clicked' + clickcount + 'times.') ؛
}) ؛
في JavaScript ، فإن الوظائف هي النوع الأول من الكائنات ، مما يعني أنه يمكنك تمرير الوظائف كمعلمات إلى وظائف أخرى. في مثالين أعلاه ، يقوم الأول بتعيين وظيفة لوظيفة أخرى ، ويقوم الأخير بتمرير الوظيفة كمعلمة إلى وظيفة أخرى. يمكن أن تصل وظيفة معالجة الأحداث (وظيفة رد الاتصال) إلى كل متغير تحت كتلة الكود حيث تحدد الوظيفة ذلك. في هذا المثال ، يمكنه الوصول إلى متغير ClickCount المحدد في إغلاق الأصل.
يكون متغير ClickCount في النطاق العالمي (النطاق الخارجي في JavaScript) ، والذي يحفظ عدد مرات النقر فوق الزر. عادة ما تكون عادة سيئة لتخزين المتغيرات تحت النطاق العالمي ، لأنه من السهل التعارض مع الكود الآخر ، ويجب أن تضع متغيرات في النطاق المحلي حيث تستخدمها. في معظم الأوقات ، مجرد لف الرمز بوظيفة واحدة يعادل إنشاء إغلاق آخر ، والتي يمكن أن تتجنب بسهولة تلويث البيئة العالمية ، تمامًا مثل هذا:
نسخة الكود كما يلي:
(وظيفة() {
var clickCount = 0 ؛
$ ('button#mybutton'). انقر فوق (function () {
ClickCount ++ ؛
ALERT ('clicked' + clickcount + 'times.') ؛
}) ؛
} ()) ؛
ملاحظة: يحدد السطر السابع من الكود أعلاه وظيفة ويطلق عليها على الفور. هذا نمط تصميم شائع في JavaScript: قم بإنشاء نطاق جديد عن طريق إنشاء وظيفة.
كيف تساعد الإغلاق البرمجة غير المتزامنة
في نموذج البرمجة القائم على الحدث ، اكتب أولاً الكود الذي يتم تشغيله بعد حدوث الحدث ، ثم ضع الكود في وظيفة ، وأخيراً تمرير الوظيفة كمعلمة إلى المتصل ، ثم اتصل بها بواسطة وظيفة المتصل لاحقًا.
في JavaScript ، الوظيفة ليست تعريفًا معزولًا. كما يتذكر سياق النطاق الذي تم الإعلان عنه. تتيح هذه الآلية وظائف JavaScript للوصول إلى السياق الذي يوجد فيه تعريف الوظيفة وجميع المتغيرات في السياق الأصل.
عندما تقوم بتمرير وظيفة رد الاتصال كمعلمة للمتصل ، سيتم استدعاء الوظيفة في وقت لاحق. حتى إذا انتهت النطاق الذي يحدد وظيفة رد الاتصال ، عندما يتم استدعاء وظيفة رد الاتصال ، لا يزال بإمكانه الوصول إلى جميع المتغيرات في النطاق النهائي ونطاقها الأم. مثل المثال الأخير ، يتم استدعاء وظيفة رد الاتصال داخل Click () من jQuery ، ولكن لا يزال بإمكانها الوصول إلى متغير ClickCount.
يظهر سحر الإغلاق في وقت سابق. يتيح لك متغيرات الدولة التي تتيح لدالة إجراء برمجة تعتمد على الحدث دون الحفاظ على الدول. ستساعدك آلية إغلاق JavaScript في الحفاظ عليها.
ملخص
البرمجة التي تعتمد على الحدث هي نموذج برمجة يحدد عملية تنفيذ البرنامج من خلال تشغيل الحدث. يسجل المبرمجون وظائف رد الاتصال للأحداث التي يهتمون بها (عادة ما تسمى معالجات الأحداث) ، ثم يقوم النظام باستدعاء معالج الحدث المسجل عند حدوث الحدث. يحتوي نموذج البرمجة هذا على العديد من المزايا التي لا تملكها نماذج البرمجة التقليدية. في الماضي ، لتنفيذ ميزات مماثلة ، يجب استخدام متعدد العمليات/متعدد الخيوط.
JavaScript هي لغة قوية بسبب نوعها الأولى من وظائف الكائن وخصائص الإغلاق ، مما يجعلها مناسبة للغاية للبرمجة التي تعتمد على الأحداث.