سؤال

هذا السيناريو:

يتم تقديم شبكة مستخدمي ، في الأساس ، نسخة مجردة من جدول بيانات. هناك مربعات نصية في كل صف في الشبكة. عندما يغيرون قيمة في مربع نص ، أقوم بإجراء التحقق من الصحة على مدخلاتهم ، وتحديث المجموعة التي تقود الشبكة ، وأعيد رسم المجاميع الفرعية على الصفحة. يتم التعامل مع كل هذا بواسطة حدث OnChange لكل مربع نص.

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

على الأقل ، هذا ما يحدث إذا قاموا بتدوين علامة التبويب عبر الزر الإرسال.

المشكلة هي ، إذا أدخلوا قيمة ، ثم انقر فوق الزر "حفظ" على الفور ، ويبدأ التنفيذ قبل إكمال userInputChanged () - حالة سباق. لا يستخدم الكود الخاص بي setTimeOut ، لكنني أستخدمه لمحاكاة رمز التحقق من صحة المستخدم البطيء:

 <!-- snip -->
 <script>
    var amount = null;
    var currentControl = null;

    function UserInputChanged(control) {
        currentControl = control;
        // use setTimeout to simulate slow validation code (production code does not use setTimeout)
        setTimeout("ValidateAmount()", 100); 
    }

    function SaveForm() {
        // call web service to save value
        document.getElementById("SavedAmount").innerHTML = amount;
    }

    function ValidateAmount() {
        // various validationey functions here
        amount = currentControl.value; // save value to collection
        document.getElementById("Subtotal").innerHTML = amount; // update subtotals

    }
</script>
<!-- snip -->
Amount: <input type="text" id="UserInputValue" onchange="UserInputChanged(this);" /> <br />
Subtotal: <span id="Subtotal"></span> <br />
<input type="button" onclick="SaveForm();" value="Save" /> <br /><br />
Saved amount: <span id="SavedAmount"></span>
<!-- snip -->

لا أعتقد أنه يمكنني تسريع رمز التحقق من الصحة - إنه خفيف الوزن للغاية ، ولكن على ما يبدو ، بطيئًا بما فيه الكفاية التي يحاول الكود الاتصال بخدمة الويب قبل اكتمال التحقق من الصحة.

على الجهاز الخاص بي ، ~ 95ms هو الرقم السحري بين ما إذا كان رمز التحقق من الصحة ينفذ قبل بدء رمز حفظ. قد يكون هذا أعلى أو أقل اعتمادًا على سرعة الكمبيوتر للمستخدمين.

هل لدى أي شخص أي أفكار كيفية التعامل مع هذه الحالة؟ اقترح زميل في العمل استخدام رمز التحقق أثناء تشغيل رمز التحقق من صحة وحلقة مشغولة في رمز الحفظ حتى تنتظر حتى يتم إلغاء تأمين الإشارة - لكنني أود تجنب استخدام أي نوع من الحلقة المزدحمة في الكود الخاص بي.

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

المحلول

استخدم الإشارة (دعنا نسميها StillneedSvalidating). إذا رأت وظيفة SaveForm أن Sytflneedsvalidating Semaphore قد ارتفع ، فاطلب من تنشيطها لسيارة ثانية خاصة بها (والتي سأسميها formneedsaving هنا) والعودة. عندما تنتهي وظيفة التحقق من الصحة ، إذا كانت Semaphore FormNeedSaving قد ارتفعت ، فإنها تستدعي وظيفة SaveForm من تلقاء نفسها.

في Jankcode ؛

function UserInputChanged(control) {
    StillNeedsValidating = true;
    // do validation
    StillNeedsValidating = false;
    if (FormNeedsSaving) saveForm(); 
}

function SaveForm() {
    if (StillNeedsValidating) { FormNeedsSaving=true; return; }
    // call web service to save value
    FormNeedsSaving = false;
}

نصائح أخرى

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

على سبيل المثال

function UserInputChanged(control) {
    // --> disable button here --< 
    currentControl = control;
    // use setTimeout to simulate slow validation code (production code does not use setTimeout)
    setTimeout("ValidateAmount()", 100); 
}

و

function ValidateAmount() {
    // various validationey functions here
    amount = currentControl.value; // save value to collection
    document.getElementById("Subtotal").innerHTML = amount; // update subtotals
    // --> enable button here if validation passes --<
}

سيتعين عليك ضبط عند إزالة setTimeout وجعل وظيفة التحقق من الصحة واحدة ، ولكن ما لم يكن لدى المستخدمين ردود فعل خارقة ، يجب أن تكون على ما يرام.

أعتقد أن المهلة تسبب مشكلتك ... إذا كان ذلك سيكون رمزًا عاديًا (لا توجد مكالمات غير متزامنة AJAX ، مهلة ، إلخ) ، فلا أعتقد أنه سيتم تنفيذ SaveForm قبل اكتمال userInputChanged.

من المحتمل أن تكون الإشارة أو mutex هي أفضل طريقة للذهاب ، ولكن بدلاً من حلقة مزدحمة ، استخدم فقط أ setTimeout() لمحاكاة نوم الخيط. مثله:

busy = false;

function UserInputChanged(control) {
    busy = true;
    currentControl = control;
    // use setTimeout to simulate slow validation code (production code does not use setTimeout)
    setTimeout("ValidateAmount()", 100); 
}

function SaveForm() {
    if(busy) 
    {
       setTimeout("SaveForm()", 10);
       return;
    }

    // call web service to save value
    document.getElementById("SavedAmount").innerHTML = amount;
}

function ValidateAmount() {
    // various validationey functions here
    amount = currentControl.value; // save value to collection
    document.getElementById("Subtotal").innerHTML = amount; // update subtotals
    busy = false;
}

يمكنك إعداد وظيفة متكررة تراقب حالة الشبكة بأكملها وتثير حدثًا يشير إلى ما إذا كانت الشبكة بأكملها صالحة أم لا.

ثم يقوم زر "إرسال النموذج" الخاص بك بتمكين نفسه أو تعطيله بناءً على هذا الحالة.

أوه ، أرى استجابة مماثلة الآن - تعمل أيضًا ، بالطبع.

عند العمل مع مصادر بيانات ASYNC ، يمكنك بالتأكيد الحصول على ظروف سباق لأن مؤشر ترابط عملية JavaScript يستمر في تنفيذ التوجيهات التي قد تعتمد على البيانات التي لم تُعود بعد من مصدر البيانات عن بُعد. لهذا السبب لدينا وظائف رد الاتصال.

في المثال الخاص بك ، تحتاج المكالمة إلى رمز التحقق من الصحة إلى وظيفة رد اتصال يمكنها القيام بشيء عند إرجاع التحقق من الصحة.

ومع ذلك ، عند صنع شيء مع منطق معقد أو محاولة لاستكشاف أو تحسين سلسلة من عمليات الاسترجاعات الحالية ، يمكنك الذهاب إلى المكسرات.

هذا هو السبب في أنني قمت بإنشاء مكتبة Proto-Q: http://code.google.com/p/proto-q/

تحقق من ذلك إذا كنت تفعل الكثير من هذا النوع من العمل.

ليس لديك حالة سباق ، لا يمكن أن تحدث ظروف السباق في JavaScript نظرًا لأن JavaScript واحد مترابط ، لذلك لا يمكن أن يتداخل خيوطان مع بعضها البعض.

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

ما يحدث على الأرجح في JavaScript الخاص بك هو أن حدث OnClick يسمى محرك JavaScript قبل أن يسمى حدث Onchange.

كتلميح ، ضع في اعتبارك أن JavaScript واحد ملولب ، إلا إذا كنت تستخدم مصحح تصحيح JavaScript (Firebug ، Microsoft Scrept Debugger). تلك البرامج تعترض الموضوع وتوقفه. من هذه النقطة على مؤشرات الترابط الأخرى (إما عن طريق الأحداث ، يمكن بعد ذلك تشغيل مكالمات SetTimeOut أو معالجات XMLHTTP) ، مما يجعل من يبدو أن JavaScript يمكنه تشغيل مؤشرات ترابط متعددة في نفس الوقت.

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