سؤال

اعتقدت أنني سأحاول أن أكون ذكيًا وأخلق وظيفة انتظار خاصة بي (أدرك أن هناك طرقًا أخرى للقيام بذلك). لذلك كتبت:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval) {
  countdowntimer = wait_interval;

  interval_id = setInterval(function() {
    --countdowntimer <=0 ? clearInterval(interval_id) : null;
  }, 1000);

  do {} while (countdowntimer >= 0);
}

// Wait a bit: 5 secs
Wait(5);

كل هذا يعمل ، باستثناء الحلقات اللانهائية. عند التفتيش ، إذا أخرجت الوقت ، يتم إدخال الوظيفة المجهولة 5 مرات ، كما هو متوقع. من الواضح أن المتغير العالمي العد التنازلي هو انخفاض.

ومع ذلك ، إذا تحقق من قيمة العد التنازلي, ، في حلقة الوقت ، لا تنخفض أبدًا. هذا على الرغم من حقيقة أن الوظيفة المجهولة يتم استدعاؤها أثناء وجودها في الحلقة!

من الواضح ، بطريقة ما ، هناك قيمتان العد التنازلي تطفو حولها ، ولكن لماذا؟

تعديل

حسنًا ، لذلك أفهم (الآن) أن JavaScript واحد ملولب. وهذا - نوع من - يجيب على سؤالي. ولكن ، عند هذه النقطة في معالجة هذا الموضوع الفردي ، لا يسمى المكالمة غير المتزامنة باستخدام setInterval في الواقع يحدث؟ هل هو فقط بين مكالمات الوظائف؟ بالتأكيد لا ، ماذا عن الوظائف التي تستغرق وقتًا طويلاً للتنفيذ؟

هل كانت مفيدة؟

المحلول

لا توجد نسختان من المتغير الكذب. JavaScript في متصفحات الويب خيوط واحدة (ما لم تستخدم أشياء جديدة لعمال الويب). لذا فإن الوظيفة المجهولة ليس لديها فرصة للتشغيل ، لأن الوظيفة Wait هو ربط المترجم.

لا يمكنك استخدام وظائف الانتهاء المزدحمة في JavaScript المستندة إلى المتصفح ؛ لن يحدث شيء آخر على الإطلاق (وهي فكرة سيئة في معظم البيئات الأخرى ، حتى في حالة إمكانية ذلك). يجب عليك استخدام عمليات الاسترجاعات بدلاً من ذلك. إليك إعادة صياغة الحد الأدنى من ذلك:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval, callback) {
    countdowntimer = wait_interval;

    interval_id = setInterval(function() {
        if (--countdowntimer <=0) {
            clearInterval(interval_id);
            interval_id = 0;
            callback();
        }
    }, 1000);
}

// Wait a bit: 5 secs
Wait(5, function() {
    alert("Done waiting");
});

// Any code here happens immediately, it doesn't wait for the callback

يحرر الرد على متابعتك:

ولكن ، عند أي نقطة في معالجة هذا الموضوع الفردي ، هل يحدث ما يسمى بالمكالمة غير المتزامنة باستخدام SetInterval بالفعل؟ هل هو فقط بين مكالمات الوظائف؟ بالتأكيد لا ، ماذا عن الوظائف التي تستغرق وقتًا طويلاً للتنفيذ؟

إلى حد كبير ، نعم-ولذا من المهم أن تكون الوظائف لا تكون طويلة الأمد. (من الناحية الفنية ، لا يتم حتى بين مكالمات الوظائف ، حيث إذا كان لديك وظيفة تستدعي ثلاث وظائف أخرى ، لا يمكن للمترجم الفوري فعل أي شيء آخر أثناء تشغيل الوظيفة (الخارجية). ينفذ. يبدأ الأمر بتنفيذ أي رمز عالمي (مثل مكالمة وظيفة كبيرة). بعد ذلك ، عندما تحدث الأمور (أحداث إدخال المستخدم ، حان الوقت للاتصال بكسل رد الاتصال المجدول عبر setTimeout تم الوصول إليه ، وما إلى ذلك) ، يدفع المترجم المترجم المكالمات التي يحتاجها إلى إجراء قائمة الانتظار. تقوم دائمًا بمعالجة المكالمة في مقدمة قائمة الانتظار ، وبالتالي يمكن أن تتراكم الأمور (مثل setInterval المكالمات ، على الرغم من setInterval هو قليل خاص - لن يصطف في طابور رد اتصال لاحق إذا كان هناك نسخة سابقة لا تزال جالسة في قائمة الانتظار في انتظار معالجتها). لذا فكر من حيث متى يتحكم الكود الخاص بك وعندما يطلق التحكم (على سبيل المثال ، بالعودة). المترجم يمكن فقط قم بأشياء أخرى بعد إطلاق السيطرة وقبل أن يعيدها لك مرة أخرى. ومرة أخرى ، في بعض المتصفحات (على سبيل المثال ، على سبيل المثال) ، يتم استخدام نفس الخيط أيضًا لطلاء واجهة المستخدم وما إلى ذلك ، لذلك لن تظهر إدخال DOM (على سبيل المثال) حتى تقوم بإصدار التحكم مرة أخرى إلى المتصفح حتى تتمكن من الحصول على على القيام برسمها.

عندما تكون JavaScript في متصفحات الويب ، فأنت بحاجة حقًا إلى اتباع نهج يحركه الحدث لتصميم حلولك وترميزها. المثال الكلاسيكي يدفع المستخدم للحصول على معلومات. في عالم غير مدفوع بالحدث ، يمكنك القيام بذلك:

// Non-functional non-event-driven pseudo-example
askTheQuestion();
answer = readTheAnswer();      // Script pauses here
doSomethingWithAnswer(answer); // This doesn't happen until we have an answer
doSomethingElse();

هذا لا يعمل في عالم يحركه الحدث. بدلاً من ذلك ، تفعل هذا:

askTheQuestion();
setCallbackForQuestionAnsweredEvent(doSomethingWithAnswer);
// If we had code here, it would happen *immediately*,
// it wouldn't wait for the answer

على سبيل المثال ، askTheQuestion قد يتراكب DIV على الصفحة مع الحقول التي تدخل المستخدم للحصول على أجزاء مختلفة من المعلومات مع زر "موافق" حتى النقر عند الانتهاء. setCallbackForQuestionAnswered سيكون حقا ربط click الحدث على زر "موافق". doSomethingWithAnswer سيقوم بجمع المعلومات من الحقول ، وإزالة أو إخفاء Div ، والقيام بشيء مع المعلومات.

نصائح أخرى

معظم تنفيذ JavaScript خيوط واحدة, ، لذلك عندما تنفذ while حلقة ، لا تدع أي شيء آخر يتم تنفيذه ، لذا فإن interval لا يركض أبدًا بينما while يركض ، مما يجعل حلقة لا حصر لها.

هناك العديد من المحاولات المماثلة لإنشاء ملف النوم/الانتظار/الإيقاف المؤقت الوظيفة في JavaScript ، ولكن نظرًا لأن معظم التطبيقات متصلة واحدة ، فإنها ببساطة لا تتيح لك القيام بأي شيء آخر أثناء النوم (!).

الطريقة البديلة لإجراء تأخير هي الكتابة مهلة. يمكنهم تأجيل تنفيذ جزء من التعليمات البرمجية ، ولكن عليك كسرها في العديد من الوظائف. يمكنك دائمًا مضمون الوظائف بحيث يسهل متابعة (ومشاركة المتغيرات ضمن نفس سياق التنفيذ).

هناك أيضًا بعض المكتبات التي تضيف بعض Suggar البصيلة إلى JavaScript مما يجعل هذا أكثر قابلية للقراءة.

تعديل:هناك منشور مدونة Excelent بواسطة جون ريج نفسه عن كيف تعمل أجهزة ضبط الوقت JavaScript. انه يشرح ذلك إلى حد كبير في التفاصيل. أتمنى أن يساعد ذلك.

في الواقع ، من المضمون إلى حد كبير أن وظيفة الفاصل الزمني لن يتم تشغيلها أبدًا في حين أن الحلقة لا تُعرف بأن JavaScript متطورة.

هناك سبب لعدم وجود أحد Wait من قبل (والكثير من حاول) ؛ انها ببساطة لا يمكن القيام به.

سيتعين عليك اللجوء إلى فرامل وظيفتك في أجزاء وجدولة هذه باستخدام SetTimeOut أو SetInterval.

//first part
...
setTimeout(function(){
    //next part
}, 5000/*ms*/);

اعتمادًا على احتياجاتك ، يمكن تنفيذ هذا (ينبغي) كآلة حالة.

بدلاً من استخدام متغير العد التنازلي العالمي ، لماذا لا تغير سمة مللي ثانية فقط على SetInterval بدلاً من ذلك؟ شيء مثل:

var waitId;

function Wait(waitSeconds)
{
    waitId= setInterval(function(){clearInterval(waitId);}, waitSeconds * 1000);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top