إذا كنت على دراية ببرمجة JavaScript من جانب العميل ، فقد تكون قد استخدمت وظائف SetTimeOut و SetInterval ، والتي تسمح للتأخير لفترة من الوقت قبل تشغيل الوظيفة. على سبيل المثال ، سيتم إضافة الكود التالي ، بمجرد تحميله على صفحة الويب ، بعد ثانية واحدة ، "Hello There" بعد مستند الصفحة:
نسخة الكود كما يلي:
var OneSecond = 1000 * 1 ؛ // ثانية واحدة = 1000 × 1 مللي ثانية
setTimeout (function () {
document.write ('<p> مرحبًا. </p>') ؛
} ، OneSecond) ؛
ويسمح SetInterval بتنفيذ وظائف متكررة على فترات زمنية محددة. إذا تم حقن الكود التالي في صفحة الويب ، فسوف يتسبب في إضافة الجملة التالية "Hello" إلى مستند الصفحة كل ثانية:
نسخة الكود كما يلي:
var OneSecond = 1000 * 1 ؛ // ثانية واحدة = 1000 × 1 مللي ثانية
setInterval (function () {
document.write ('<p> مرحبًا. </p>') ؛
} ، OneSecond) ؛
نظرًا لأن الويب أصبح منذ فترة طويلة منصة لبناء التطبيقات ، بدلاً من صفحة ثابتة بسيطة ، فإن هذا النوع من الطلب المماثل يبرز بشكل متزايد. تساعد وظائف تخطيط المهام هذه المطورين على تنفيذ التحقق الدوري للنماذج ، أو تأخير مزامنة البيانات عن بُعد ، أو تفاعلات واجهة المستخدم التي تتطلب استجابات متأخرة. العقدة تنفذ أيضا هذه الطرق بالكامل. على جانب الخادم ، يمكنك استخدامها لتكرار أو تأخير تنفيذ العديد من المهام ، مثل انتهاء صلاحية ذاكرة التخزين المؤقت ، وتنظيف تجمعات الاتصال ، وانتهاء الجلسة ، والاقتراع ، وأكثر من ذلك.
تنفذ باستخدام وظيفة تأخير setTimeout
يمكن لـ SetTimeout إنشاء خطة تنفيذ تدير الوظيفة المحددة مرة واحدة في وقت معين في المستقبل ، مثل:
نسخة الكود كما يلي:
var timeout_ms = 2000 ؛ // 2 ثانية
var timeout = setTimeOut (function () {
console.log ("توقيت الخروج!") ؛
} ، timeout_ms) ؛
مثل العميل JavaScript ، يقبل SetTimeout معلمتين. المعلمة الأولى هي الوظيفة التي يجب تأخيرها ، والمعلمة الثانية هي وقت التأخير (بالميلي ثانية).
يقوم SetTimeOut بإرجاع مقبض مهلة ، وهو كائن داخلي. يمكنك استخدامه كمعلمة للاتصال ClearTimeOut بإلغاء المؤقت. إلا أن هذا المقبض ليس له أي تأثير.
استخدم ClearTimeOut لإلغاء خطة التنفيذ
بمجرد الحصول على مقبض المهلة ، يمكنك استخدام ClearTimeOut لإلغاء خطة تنفيذ الوظائف ، مثل هذا:
نسخة الكود كما يلي:
var timeOutTime = 1000 ؛ // ثانية واحدة
var timeout = setTimeOut (function () {
console.log ("توقيت الخروج!") ؛
} ، timeouttime) ؛
ClearTimeout (مهلة) ؛
في هذا المثال ، لن يتم تشغيل المؤقت أبدًا ولن يخرج الكلمات "Time Out!". يمكنك أيضًا إلغاء خطة التنفيذ في أي وقت في المستقبل ، مثل المثال التالي:
نسخة الكود كما يلي:
var timeout = setTimeOut (الدالة A () {
console.log ("توقيت الخروج!") ؛
} ، 2000) ؛
setTimeout (الوظيفة B () {
ClearTimeout (مهلة) ؛
} ، 1000) ؛
يحدد الرمز وظيفتين A و B الذي تم تنفيذه المتأخران. من المقرر تنفيذ الوظيفة A بعد ثانيتين ، ومن المقرر تنفيذ B بعد ثانية واحدة ، لأن الوظيفة B يتم تنفيذها أولاً ، وتلغي خطة تنفيذ A ، لذلك لن يتم تشغيل A أبدًا.
تطوير وإلغاء خطة التنفيذ المتكررة للوظيفة
يشبه SetInterval setTimeOut ، لكنه سيتم تنفيذ وظيفة مرارًا وتكرارًا في فترة زمنية محددة. يمكنك استخدامه لإثارة برنامج دوري لإكمال بعض المهام الأخرى التي تحتاج إلى تكرار ، مثل التنظيف ، والتجميع ، والتسجيل ، والحصول على البيانات ، والاستطلاع ، إلخ.
سيتم إخراج الكود التالي "علامة" إلى وحدة التحكم كل ثانية:
نسخة الكود كما يلي:
الفترة الفار = 1000 ؛ // 1 ثانية
setInterval (function () {
console.log ("tick") ؛
}، فترة)؛
إذا كنت لا تريد أن تعمل إلى الأبد ، فيمكنك استخدام ClearInterval () لإلغاء المؤقت.
يقوم SetInterval بإرجاع مقبض خطة التنفيذ ، والذي يمكن استخدامه كمعلمة لإزالة EnterInterval لإلغاء خطة التنفيذ:
نسخة الكود كما يلي:
var interval = setInterval (function () {
console.log ("tick") ؛
} ، 1000) ؛
// ...
clearinterval (الفاصل) ؛
استخدم Process.NextTick لتأخير تنفيذ الوظيفة إلى الجولة التالية من حلقة الحدث
في بعض الأحيان ، يستخدم مبرمج JavaScript Client SetTimeOut (رد الاتصال ، 0) لتأخير المهمة لفترة قصيرة من الزمن. المعلمة الثانية هي 0 مللي ثانية. يخبر JavaScript بتنفيذ وظيفة رد الاتصال هذه مباشرة بعد معالجة جميع الأحداث المعلقة. في بعض الأحيان يتم استخدام هذه التقنية لتأخير تنفيذ العمليات التي لا تحتاج إلى تنفيذها على الفور. على سبيل المثال ، في بعض الأحيان تحتاج إلى بدء تشغيل الرسوم المتحركة أو إجراء بعض الحسابات الأخرى بعد معالجة حدث المستخدم.
في العقدة ، تمامًا مثل المعنى الحرفي لـ "حلقة الحدث" ، تعمل حلقة الحدث في حلقة تعالج قوائم قوائم الأحداث ، ويسمى كل جولة في حلقة الحدث علامة.
يمكنك الاتصال بوظيفة رد الاتصال بمجرد أن تبدأ حلقة الحدث في تنفيذ الجولة التالية (القاعدة التالية) ، وهو بالضبط مبدأ Process.NextTick ، ويستخدم SetTimeout ، SetTimeout قائمة انتظار التنفيذ داخل وقت تشغيل JavaScript ، بدلاً من استخدام حلقة الحدث.
باستخدام Process.NextTick (رد الاتصال) بدلاً من SetTimeOut (رد الاتصال ، 0) ، سيتم تنفيذ وظيفة رد الاتصال الخاصة بك مباشرة بعد معالجة الحدث في قائمة الانتظار. إنه أسرع بكثير من قائمة انتظار المهلة JavaScript (تقاس بوقت وحدة المعالجة المركزية).
يمكنك تأخير الوظيفة حتى حلقة الحدث التالية وتشغيلها على هذا النحو:
نسخة الكود كما يلي:
Process.NextTick (function () {
my_expension_computation_function () ؛
}) ؛
ملاحظة: كائن العملية هو أحد الكائنات العالمية القليلة في العقدة.
حظر حلقة الحدث
يستخدم وقت تشغيل Node و JavaScript حلقة حدث واحد. كل حلقة ، يستخدم وقت التشغيل وظيفة رد الاتصال للتعامل مع الحدث التالي في قائمة الانتظار. عند تنفيذ الحدث ، تحصل حلقة الحدث على نتيجة التنفيذ وتعالج الحدث التالي ، مع تكرار ذلك حتى تصبح قائمة انتظار الحدث فارغة. إذا استغرقت إحدى عمليات الاسترجاعات وقتًا طويلاً للتشغيل ، فلن تتمكن حلقة الحدث من التعامل مع الأحداث المعلقة الأخرى خلال ذلك الوقت ، مما قد يجعل التطبيق أو الخدمة بطيئة للغاية.
عند معالجة الأحداث ، إذا تم استخدام وظائف حساسة للذاكرة أو حساسة للمعالج ، ستصبح حلقة الحدث بطيئة ، وسوف تتراكم عدد كبير من الأحداث ، والتي لا يمكن معالجتها في الوقت المناسب ، أو حتى منع قائمة الانتظار.
انظر المثال التالي لحلق حلقة الحدث:
نسخة الكود كما يلي:
Process.NextTick (وظيفة NextTick1 () {
var a = 0 ؛
بينما (صحيح) {
A ++ ؛
}
}) ؛
Process.NextTick (وظيفة NextTick2 () {
console.log ("next trick") ؛
}) ؛
setTimeout (timeout timeout () {
console.log ("timeout") ؛
} ، 1000) ؛
في هذا المثال ، ليس لدى NextTick2 ووظائف المهلة أي فرصة للتشغيل بغض النظر عن المدة التي تنتظرها ، لأن حلقة الحدث قد تم حظرها بواسطة حلقة Infinite في وظيفة NextTick ، ولن يتم تشغيلها حتى إذا كان من المقرر تنفيذ وظيفة المهلة بعد ثانية واحدة.
عند استخدام SetTimeOut ، تتم إضافة وظائف رد الاتصال إلى قائمة انتظار خطة التنفيذ ، وفي هذه الحالة لم تتم إضافتها إلى قائمة الانتظار. على الرغم من أن هذا مثال متطرف ، يمكنك أن ترى أن تشغيل مهمة حساسة للمعالج يمكن أن يحظر أو إبطاء حلقة الحدث.
الخروج من حلقة الحدث
باستخدام Process.NextTick ، يمكن تأجيل مهمة غير حرجة إلى الجولة التالية من حلقة الحدث (TICK) قبل التنفيذ ، والتي يمكن أن تحرر حلقة الحدث حتى يتمكن من الاستمرار في تنفيذ الأحداث المعلقة الأخرى.
انظر المثال التالي. إذا كنت تخطط لحذف ملف مؤقت ولكن لا تريد وظيفة رد الاتصال في حدث البيانات لانتظار عملية IO هذه ، فيمكنك تأخيره على هذا النحو:
نسخة الكود كما يلي:
Dream.on ("البيانات" ، الدالة (البيانات) {
Stream.end ("ردي") ؛
Process.NextTick (function () {
fs.unlink ("/path/to/file") ؛
}) ؛
}) ؛
استخدم setTimeOut بدلاً من setInterval لضمان تسلسل تنفيذ الوظيفة
لنفترض أنك تخطط لتصميم وظيفة تسمى my_async_function ، والتي يمكنها القيام ببعض عمليات الإدخال/الإخراج (مثل تحليل ملفات سجل) وتعزيز تنفيذها بشكل دوري. يمكنك تنفيذه باستخدام SetInterval مثل هذا:
نسخة الكود كما يلي:
var الفاصل = 1000 ؛
setInterval (function () {
my_async_function (function () {
console.log ('my_async_function الانتهاء!') ؛
}) ؛
} ، الفاصل الزمني) ؛ // ملاحظة المترجم: لقد أضفت السابق "، الفاصل الزمني" ويجب أن يكون المؤلف قد فاته بسبب خطأ مطبعي
يجب أن تكون قادرًا على التأكد من عدم تنفيذ هذه الوظائف في وقت واحد ، ولكن إذا كنت تستخدم SetInterval ، فلا يمكنك ضمان ذلك. إذا كانت وظيفة my_async_function تعمل لفترة أطول من متغيرات الفاصل الزمني ، فسيتم تنفيذها في وقت واحد ، بدلاً من التسلسل التسلسلي.
ملاحظة المترجم: (يتم إضافة الجزء الغامق أدناه بواسطة المترجم ، وليس محتوى الكتاب الأصلي)
لتسهيل فهم هذا الجزء من المحتوى ، يمكنك تعديل رمز المؤلف حتى يتمكن بالفعل من تشغيل:
نسخة الكود كما يلي:
var الفاصل = 1000 ؛
setInterval (function () {
(وظيفة my_async_function () {
setTimeout (function () {
console.log ("1") ؛
} ، 5000) ؛
}) () ؛
}،فاصلة)؛
قم بتشغيل هذا الرمز وستجد أنه بعد انتظار 5 ثوان ، يتم إخراج "Hello" كل ثانية واحدة. نتوقع أنه بعد تنفيذ my_async_function الحالي (تم أخذها 5 ثوان) ، انتظر ثانية واحدة قبل تنفيذ my_async_function التالي ، ويجب أن يكون الفاصل الزمني بين كل مخرج 6 ثوانٍ. هذه النتيجة لأن my_async_function لم يتم تنفيذها بشكل متسلسل ، ولكن يتم تشغيلها في نفس الوقت.
لذلك ، تحتاج إلى طريقة لفرض الفاصل الزمني بين نهاية تنفيذ my_async_function وبدء تنفيذ my_async_function التالي هو بالضبط الوقت المحدد بواسطة المتغير الفاصل. يمكنك القيام بذلك:
نسخة الكود كما يلي:
var الفاصل = 1000 ؛ // 1 ثانية
(جدول الوظائف () {// السطر 3
setTimeout (وظيفة do_it () {
my_async_function (function () {// line 5
console.log ('async يتم!') ؛
جدول()؛
}) ؛
}، فاصلة)؛
} ()) ؛ // الخط 10
في الكود السابق ، يتم الإعلان عن وظيفة تسمى الجدول (السطر 3) ، ويتم استدعاؤها مباشرة بعد الإعلان (السطر 10). ستقوم وظيفة الجدول الزمني بتشغيل وظيفة do_it بعد ثانية واحدة (محددة بواسطة الفاصل الزمني). بعد ثانية واحدة ، سيتم استدعاء وظيفة my_async_function في السطر 5. عند تنفيذها ، سوف يطلق على وظيفة رد الاتصال المجهولة (السطر 6). ستعمل وظيفة رد الاتصال المجهول على إعادة تعيين خطة تنفيذ DO_IT مرة أخرى وتركها يتم تنفيذها مرة أخرى بعد ثانية واحدة ، بحيث يبدأ الرمز بشكل متسلسل ومستمر.
ملخص
يمكنك استخدام وظيفة setTimeOut () لإعداد خطة تنفيذ الوظيفة مسبقًا وإلغاءها باستخدام وظيفة ClearTimeOut (). يمكنك أيضًا استخدام SetInterval () لتنفيذ وظيفة معينة بشكل دوري بشكل متكرر. وفقًا لذلك ، يمكنك استخدام ClearInterval () لإلغاء خطة التنفيذ المتكررة هذه.
إذا تم حظر حلقة الحدث باستخدام عملية حساسة للمعالج ، فستتأخر الوظائف التي تم التخطيط لها في الأصل لتنفيذها ولن يتم تنفيذها أبدًا. لذلك لا تستخدم عمليات حساسة وحدة المعالجة المركزية داخل حلقة الحدث. أيضًا ، يمكنك استخدام Process.nextTick () لتأخير تنفيذ الوظيفة حتى الجولة التالية من حلقة الحدث.
عند استخدام I/O و SetInterval () معًا ، لا يمكنك ضمان وجود مكالمة واحدة معلقة في أي وقت ، ولكن يمكنك استخدام وظائف متكررة ووظائف SetTimeOut () لتجنب هذه المشكلة الصعبة.