سؤال

لدي تطبيق ويب حيث يوجد مؤقت يتم عددًا باستمرار. وفي الوقت نفسه ، يتحقق العميل بشكل متكرر مع الخادم لمعرفة ما إذا كان قد تمت إضافة المزيد من الوقت إلى المؤقت. الرمز يشبه هذا:

function tick() {
    // This function is called once every second
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    time = newtime;
};

إنه ، بالطبع ، أكثر تعقيدًا من ذلك ، لكن يمكنك رؤية حالة العرق المتأصلة. ماذا لو كان التحديث ووظيفة القراد يحاولان تعديلهما time في نفس الوقت؟

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

شكرًا لك.

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

المحلول

ليس لديك حالة سباق ، لأن JavaScript لا يتم تنفيذها بشكل متزامن.

في كل مرة يتم فيها إطلاق ردهة من عملية غير متزامنة (Ajax ، setTimeout, ، وما إلى ذلك) ، يجب أن ينتهي رد الاتصال هذا قبل إعادة الاتصال إلى آخر من عملية غير متزامنة أخرى. حتى إذا update() قيد التشغيل ، لا يوجد جافا سكريبت آخر. مرة واحدة update() التشطيبات ، يمكن إطلاق عمليات الاسترداد الأخرى من عمليات ASYNC (على سبيل المثال ، tick()). ومن المثير للاهتمام أن هذا هو السبب أيضًا setTimeout ولا يضمن تنفيذ أمثالها في اللحظة المحددة الوصول إلى المهلة: يمكن لبعض JavaScript الأخرى منع تنفيذ رد الاتصال.

الدفع http://ejohn.org/blog/how-javascript-timers-work/ للحصول على بعض المعلومات الجيدة حول كيفية عمل كل هذا.

نصائح أخرى

JavaScript هو واحد الخيوط. لا يوجد حالة سباق. لا توجد طريقة في JavaScript للخطرين time = newtime; و time -= 1; للتداخل أثناء التنفيذ. في الواقع ، يتم ضمان عدم التداخل في وظيفتين. واحد منهم سوف يعمل وبعد ذلك سيتم تشغيل الآخر.

كنت مخطئا: هذا لا يحل المشكلة! (شرح بعد الكود)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

المشكلة في هذا الحل الخاطئ هي أن تفعل بهذه الطريقة تنقل مشكلة حالة السباق من المتغير time إلى متغير NEWTIME.

فقط فكر في هذا: تنفيذ tick يصل وتنفذ الخط time = NEWTIME; الآن ، قبل المتابعة ، يتم استدعاء التحديث و NEWTIME يحصل على قيمة X. يستمر تنفيذ القراد الآن في التنفيذ NEWTIME = false;. بهذه الطريقة فقدت X قيمة ال NEWTIME وهكذا تأثير مكالمة التحديث ()!

المشكلة تحتاج إلى بعض الإشارات. أفعل ذلك كثيرًا لإرسال أياكس بعد الانتهاء السابق. حالتك متشابهة بعض الشيء ؛)

جرب شيئًا كهذا. يجب أن تتجاهل جميع المحاولات لخفض الوقت الذي يصطدم مع رد الاتصال Ajax.

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

شيء آخر - يعمل SetTimeout مثل موضوع جديد وأتوقع أن تقوم المتصفحات بالوصول إلى MEM المزامنة ، لذلك قد يكون ذلك كافياً للتحقق مما إذا كانت القيمة لم تنمو قبل الانخفاض. لكن الحل أعلاه أكثر مرونة وآمنة.

ونصيحة صغيرة - تجنب الاستعلام مع أياكس في كثير من الأحيان - قد تسبب مشاكل إضافية - مثل الطلبات التي تعود بترتيب مختلف عن إرسالها ، واستخدام ذاكرة Firefox يزيد كثيرًا على الكثير من Ajax في الدقيقة ؛)

طالما قمت بإضافة بعض الثواني الأخرى لك الوقت الحالي يجب أن تكون بخير.

بدلا من القيام time = newtime; محاولة time += newtime; وبهذه الطريقة لن تخسر الثانية التي أنت قلق عليها.

ومع ذلك ، فأنت تفقد ثانية فقط في أسوأ الأحوال.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top