سؤال

هذا هو أول وظيفة على ستاكوفيرفلوو, لذا يرجى لا لهب لي من الصعب جدا إذا كنت تأتي عبر مثل مجموع مغفل أو إذا أنا غير قادر على ot جعل نفسي واضح تماما.:-)

هنا مشكلتي:أنا أحاول أن أكتب وظيفة جافا سكريبت أن "العلاقات" الوظيفتين إلى آخر عن طريق التحقق أول واحد الإنجاز ومن ثم تنفيذ ثانية واحدة.

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

فكرتي عن حل لإعطاء أول وظيفة العلم "" ، أيمما يجعل إنشاء الممتلكات العامة "هذا.الزناد" (تهيئة "0" تعيين إلى "1" عند الانتهاء) مرة واحدة ويسمى;تفعل ذلك يجب أن تجعل من الممكن بالنسبة وظيفة أخرى للتحقق من العلم قيمته ([0,1]).إذا كان الشرط ("الزناد == 1") الوظيفة الثانية يجب أن تحصل على ما يسمى.

التالي هو مثال مجردة البرمجية التي استخدمت للاختبار:

<script type="text/javascript" >

/**/function cllFnc(tgt) { //!! first function

    this.trigger = 0 ;
    var trigger = this.trigger ;

    var _tgt = document.getElementById(tgt) ; //!! changes the color of the target div to signalize the function's execution
        _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

            trigger = 1 ;

    },5000) ;

}

/**/function rcvFnc(tgt) { //!! second function that should get called upon the first function's completion

    var _tgt = document.getElementById(tgt) ; //!! changes color of the target div to signalize the function's execution
        _tgt.style.background = '#f63' ;

    alert('... Someone picked up!') ;

}

/**/function callCheck(obj) {   

            //alert(obj.trigger ) ;      //!! correctly returns initial "0"                         

    if(obj.trigger == 1) {              //!! here's the problem: trigger never receives change from function on success and thus function two never fires 

                        alert('trigger is one') ;
                        return true ;
                    } else if(obj.trigger == 0) {
                        return false ;
                    }


}

/**/function tieExc(fncA,fncB,prms) {

        if(fncA == 'cllFnc') {
            var objA = new cllFnc(prms) ;   
            alert(typeof objA + '\n' + objA.trigger) ;  //!! returns expected values "object" and "0"
        } 

        //room for more case definitions

    var myItv = window.setInterval(function() {

        document.getElementById(prms).innerHTML = new Date() ; //!! displays date in target div to signalize the interval increments


        var myCallCheck = new callCheck(objA) ; 

            if( myCallCheck == true ) { 

                    if(fncB == 'rcvFnc') {
                        var objB = new rcvFnc(prms) ;
                    }

                    //room for more case definitions

                    window.clearInterval(myItv) ;

            } else if( myCallCheck == false ) {
                return ;
            }

    },500) ;

}

</script>

HTML جزء في الاختبار:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd >

<html>

<head>

    <script type="text/javascript" >
       <!-- see above -->
    </script>

    <title>

      Test page

    </title>


</head>

<body>

    <!-- !! testing area -->

        <div id='target' style='float:left ; height:6em ; width:8em ; padding:0.1em 0 0 0; font-size:5em ; text-align:center ; font-weight:bold ; color:#eee ; background:#fff;border:0.1em solid #555 ; -webkit-border-radius:0.5em ;' >
            Test Div
        </div>

        <div style="float:left;" >
            <input type="button" value="tie calls" onmousedown="tieExc('cllFnc','rcvFnc','target') ;" />
        </div>

<body>


</html>

أنا متأكد من أن هذا هو بعض المسألة مع جافا سكريبت نطاق كما يجب فحص ما إذا كان الزناد يحصل تعيين إلى "1" بشكل صحيح وأنه لا.من المرجح جدا "checkCall()" وظيفة لا يحصل على تحديث كائن ولكن بدلا من ذلك فقط الشيكات القديمة سبيل المثال والتي من الواضح لم أعلام الانتهاء من إعداد "هذا.الزناد" إلى "1".إذا كنت لا تعرف كيفية معالجة هذه المسألة.

على أية حال آمل شخص لديه فكرة أو تجربة مع هذا النوع من المشكلة.

شكرا على القراءة!

FK

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

المحلول 4

لقد عملت بها ويبدو أن تعمل بشكل جيد تماما الآن.أنا سيتم نشر قانون بلدي في وقت لاحق بعد فرز بها.في غضون ذلك, شكرا جزيلا لك على المساعدة!

التحديث

جربت الكود في بكت (سفاري, كروم) ، موزيلا و أوبرا.يبدو أن تعمل على ما يرام.نتطلع إلى أي ردود.

تحديث 2

لقد غيرت tieExc() طريقة لدمج Anurag مقيدة استدعاء دالة بناء الجملة.الآن يمكنك استدعاء العديد من الوظائف كما تريد وعند الانتهاء من التحقق عن طريق تمرير لهم الحجج.

إذا كنت لا تميل إلى قراءة رمز ، في محاولة منه: http://jsfiddle.net/UMuj3/ (راجع للشغل ، JSFiddle هو موقع أنيق حقا!).

JS-كود:

/**/function meta() {

var myMeta = this ;

/**  **/this.cllFnc = function(tgt,lgt) { //!! first function

    this.trigger = 0 ;  //!! status flag, initially zero
    var that = this ;   //!! required to access parent scope from inside nested function

    var _tgt = document.getElementById(tgt) ; //!! changes the color of the target div to signalize the function's execution
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! simulates longer AJAX call, duration 5000ms

        that.trigger = 1 ;  //!! status flag, one upon completion

    },5000) ;

} ;

/**  **/this.rcvFnc = function(tgt) { //!! second function that should get called upon the first function's completion

    var _tgt = document.getElementById(tgt) ; //!! changes color of the target div to signalize the function's execution
    _tgt.style.background = '#f63' ;

    alert('... Someone picked up!') ;

} ;

/**  **/this.callCheck = function(obj) {    

    return (obj.trigger == 1)   ?   true
        :   false
        ;

} ;

/**  **/this.tieExc = function() {

    var functions = arguments ;

    var myItv = window.setInterval(function() {

        document.getElementById('target').innerHTML = new Date() ; //!! displays date in target div to signalize the interval increments

        var myCallCheck = myMeta.callCheck(functions[0]) ; //!! checks property "trigger"

        if(myCallCheck == true) { 

            clearInterval(myItv) ;

            for(var n=1; n < functions.length; n++) {

                functions[n].call() ;

            }

        } else if(myCallCheck == false) { 
            return ;
        }

    },100) ;



} ;

}​

HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd >

<html>

<head>

    <script type='text/javascript'  >
        <!-- see above -->
    </script>
    <title>

      Javascript Phased Execution Test Page

    </title>

</head>

<body>

        <div id='target' style='float:left ; height:7.5em ; width:10em ; padding:0.5em 0 0 0; font-size:4em ; text-align:center ; font-weight:bold ; color:#eee ; background:#fff;border:0.1em solid #555 ; -webkit-border-radius:0.5em ;' >
            Test Div
        </div>

        <div style="float:left;" >
            <input type="button" value="tieCalls()" onmousedown="var myMeta = new meta() ; var myCll = new myMeta.cllFnc('target') ; new myMeta.tieExc(myCll, function() { myMeta.rcvFnc('target') ; }, function() { alert('this is fun stuff!') ; } ) ;" /><br />
        </div>

<body>


</html>

نصائح أخرى

يمكنك الاستفادة من ميزة من شبيبة يسمى الإغلاق.الجمع بين هذا مع شائعة جدا شبيبة نمط يسمى "استمرار يمر على غرار" و لديك الحل الخاص بك.(أيا من هذه الأمور الأصلي JS, ولكن تستخدم بشكل كبير في JS).

// a function
function foo(some_input_for_foo, callback)
{
    // do some stuff to get results

    callback(results); // call our callback when finished
}

// same again
function bar(some_input_for_bar, callback)
{
    // do some stuff to get results

    callback(results); // call our callback when finished
}

"استمرار يمر على غرار" يشير إلى رد.بدلا من إرجاع قيمة كل المكالمات وظيفة رد الاتصال (استمرار) و يعطي نتائج.

ثم يمكنك ربط الاثنين معا بسهولة:

foo(input1, function(results1) {

    bar(results1, function(results2) {

        alert(results2);
    });
});

متداخلة وظائف مجهولة يمكن "رؤية" المتغيرات من نطاق يعيشون فيه.لذلك ليس هناك حاجة إلى استخدام خصائص خاصة لتمرير المعلومات حولها.

التحديث

أن توضح في سؤالك هذا مقتطف الشفرة ، فمن الواضح أن كنت تفكر في ما يقرب من هذا القبيل:

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

(ثم عامل تعقيد, حلقة إلى استخدام setInterval لبدء التشغيل ، clearInterval إلى الإقلاع عن التدخين ، للسماح أخرى JS التعليمات البرمجية لتشغيل - لكنه في الأساس "الاقتراع حلقة" مع ذلك).

أنت لست بحاجة إلى أن تفعل ذلك!

بدلا من إجراء أول وظيفة تعيين الخاصية على الانتهاء ، تجعل من استدعاء دالة.

أن يكون هذا واضحا ، دعونا ريفاكتور الأصلي الخاص بك التعليمات البرمجية:

function cllFnc(tgt) { //!! first function

    this.trigger = 0 ;
    var trigger = this.trigger ;

    var _tgt = document.getElementById(tgt) ; //!! changes the color...
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

        trigger = 1 ;

    },5000) ;
}

[تحديث 2:بالمناسبة, هناك خلل هناك.نسخ القيمة الحالية trigger الملكية في متغير محلي جديد يسمى trigger.ثم في النهاية يمكنك تعيين 1 إلى المتغير المحلي.لا أحد سيكون قادرا على رؤية ذلك.المتغيرات المحلية خاصة إلى وظيفة. لكنك لست بحاجة إلى أن تفعل أي شيء من هذا على أي حال ، حتى تبقى القراءة...]

كل ما علينا القيام به هو معرفة أن وظيفة ما يطلق عندما يكون القيام به, و التخلص من الممتلكات-الإعداد:

function cllFnc(tgt, finishedFunction) { //!! first function

    var _tgt = document.getElementById(tgt) ; //!! changes the color...
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

        finishedFunction(); // <-------- call function instead of set property

    },5000) ;
}

هناك الآن حاجة بك "دعوة الاختيار" أو خاص بك tieExc المساعد.يمكنك بسهولة ربط الوظيفتين معا مع القليل جدا من التعليمات البرمجية.

var mySpan = "#myspan";

cllFnc(mySpan, function() { rcvFnc(mySpan); });

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

على سبيل المثال, أول وظيفة قد تفعل بضعة المكالمات اياكس خدمة (باستخدام مسج الإيجاز):

function getCustomerBillAmount(name, callback) {

    $.get("/ajax/getCustomerIdByName/" + name, function(id) {

        $.get("/ajax/getCustomerBillAmountById/" + id), callback);

    });
}

هنا ، callback يقبل العميل مبلغ الفاتورة ، و اياكس get دعوة يمر تلقى قيمة الدالة نمر, لذا callback متوافق بالفعل و لذلك يمكن مباشرة بمثابة الاستدعاء الثاني اياكس الاتصال.لذلك هذا هو في حد ذاته مثال على ربط اثنين من الاستدعاءات غير المتزامنة معا في تسلسل التفاف عليها في ما يبدو (من الخارج) أن تكون مفردة غير متزامن وظيفة.

ثم يمكننا أن سلسلة هذا مع عملية أخرى:

function displayBillAmount(amount) {

    $("#billAmount").text(amount); 
}

getCustomerBillAmount("Simpson, Homer J.", displayBillAmount);

أو يمكننا أن (مرة أخرى) قد استخدمت وظيفة مجهول:

getCustomerBillAmount("Simpson, Homer J.", function(amount) {

    $("#billAmount").text(amount); 
});

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

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

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

تحديث 3

أرى في أي مكان آخر في التعليقات أذكر لكم أن المشكلة الفعلية هي التخزين المؤقت النتائج ، لذلك كل ما عندي من العمل موضحا أن هذا مضيعة للوقت.هذا هو النوع من الشيء يجب أن تضع في السؤال.

تحديث 4

في الآونة الأخيرة لقد كتبت بلوق وظيفة قصيرة في موضوع التخزين المؤقت غير متزامن دعوة النتائج في جافا سكريبت.

(نهاية التحديث 4)

هناك طريقة أخرى لمشاركة النتائج هو توفير وسيلة واحدة رد على "بث" أو "نشر" إلى العديد من المشتركين:

function pubsub() {
    var subscribers = [];

    return {
        subscribe: function(s) {
            subscribers.push(s);
        },
        publish: function(arg1, arg2, arg3, arg4) {
            for (var n = 0; n < subscribers.length; n++) {
                subscribers[n](arg1, arg2, arg3, arg4);
            }
        }
    };
}

لذلك:

finished = pubsub();

// subscribe as many times as you want:

finished.subscribe(function(msg) {
    alert(msg);
});

finished.subscribe(function(msg) {
    window.title = msg;
});

finished.subscribe(function(msg) {
    sendMail("admin@mysite.com", "finished", msg);
});

ثم السماح لبعض بطء عملية نشر النتائج:

lookupTaxRecords("Homer J. Simpson", finished.publish);

عندما مكالمة واحدة التشطيبات الآن استدعاء كل ثلاثة المشتركين.

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

function ajax(url) {
    var req = new XMLHttpRequest();  
    req.open('GET', url, true);  
    req.onreadystatechange = function (aEvt) {  
        if(req.readyState == 4)
            alert("Ready!")
    }
    req.send(null);  
}

بالطبع ، هذا ليس مرنًا بدرجة كافية ، لأننا نريد إجراء إجراءات مختلفة لمكالمات Ajax المختلفة. لحسن الحظ ، JavaScript هي لغة وظيفية ، لذلك يمكننا ببساطة تمرير الإجراء المطلوب كمعلمة:

function ajax(url, action) {
    var req = new XMLHttpRequest();  
    req.open('GET', url, true);  
    req.onreadystatechange = function (aEvt) {  
        if(req.readyState == 4)
            action(req.responseText);
    }
    req.send(null);  
}

يمكن استخدام هذه الوظيفة الثانية مثل هذه:

 ajax("http://...", function(text) {
      do something with ajax response  
 });

وفقًا للتعليقات ، هنا مثال على كيفية استخدام Ajax داخل كائن ما

function someObj() 
{
    this.someVar = 1234;

    this.ajaxCall = function(url) {
        var req = new XMLHttpRequest();  
        req.open('GET', url, true);  

        var me = this; // <-- "close" this

        req.onreadystatechange = function () {  
            if(req.readyState == 4) {
                // save data...
                me.data = req.responseText;     
                // ...and/or process it right away
                me.process(req.responseText);   

            }
        }
        req.send(null);  
    }

    this.process = function(data) {
        alert(this.someVar); // we didn't lost the context
        alert(data);         // and we've got data!
    }
}


o = new someObj;
o.ajaxCall("http://....");

والفكرة هي "إغلاق" (الاسم المستعار) "هذا" في معالج الأحداث ، بحيث يمكن تمريره أكثر.

مرحبا بكم في ذلك!راجع للشغل, كنت تأتي عبر مجموع مغفل و سؤالك غير واضح تماما :)

هذا بناء على @دانيال الجواب من استخدام متابعات.وهي وظيفة بسيطة أن سلاسل أساليب متعددة معا.مثل كيف الأنابيب | يعمل في يونكس.فإنه يأخذ مجموعة من الوظائف كما الحجج التي سيتم تنفيذها بالتتابع.قيمة الإرجاع من كل استدعاء الدالة يتم تمرير إلى المرحلة التالية وظيفة كمعلمة.

function Chain() {
    var functions = arguments;

    return function(seed) {
        var result = seed;

        for(var i = 0; i < functions.length; i++) {
            result = functions[i](result);
        }

        return result;
    }
}

لاستخدامه, إنشاء كائن من Chained اجتياز جميع وظائف المعلمات.على سبيل المثال يمكنك اختبار كمان سيكون:

​var chained = new Chain(
    function(a) { return a + " wo"; },
    function(a) { return a + "r"; },
    function(a) { return a + "ld!"; }
);

alert(chained('hello')); // hello world!

مع إستخدام AJAX طلب تمرير بالسلاسل بمثابة نجاح الاستدعاء إلى مدعوم.

​var callback = new Chain(
    function(response) { /* do something with ajax response */ },
    function(data) { /* do something with filtered ajax data */ }
);

var req = new XMLHttpRequest();  
req.open('GET', url, true);  
req.onreadystatechange = function (aEvt) {  
    if(req.readyState == 4)
        callback(req.responseText);
}
req.send(null);  

الشيء المهم هو أن كل وظيفة يعتمد على الناتج السابق وظيفة, لذلك يجب أن عودة بعض القيمة في كل مرحلة.


هذا مجرد اقتراح - إعطاء مسؤولية التحقق من ما إذا كانت البيانات المتاحة محليا أو طلب HTTP يجب أن يكون هو الذهاب الى زيادة تعقيد النظام.بدلا من ذلك, يمكن أن تكون مبهمة طلب مدير الكثير من تحب metaFunction لديك, والسماح لها أن تقرر إذا كانت البيانات التي يتم تقديم محليا أو عن بعد.

هنا عينة Request وجوه أن يتعامل مع هذا الوضع دون أي كائنات أخرى أو وظائف معرفة أين البيانات من:

var Request = {
    cache: {},

    get: function(url, callback) {
        // serve from cache, if available
        if(this.cache[url]) {
            console.log('Cache');
            callback(this.cache[url]);
            return;
        }
        // make http request
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        var self = this;
        request.onreadystatechange = function(event) {
            if(request.readyState == 4) {
                self.cache[url] = request.responseText;
                console.log('HTTP');
                callback(request.responseText);
            }
        };
        request.send(null);
    }
};

لاستخدامه, يمكنك إجراء مكالمة Request.get(..), تقوم بإرجاع البيانات المخزنة مؤقتا إذا كانت متوفرة أو يجعل اياكس الاتصال خلاف ذلك.معلمة ثالث يمكن تمريرها إلى ما يجب أن تكون البيانات المخزنة مؤقتا إذا كنت تبحث عن الحبيبية التحكم في التخزين المؤقت.

Request.get('<url>', function(response) { .. }); // HTTP
// assuming the first call has returned by now
Request.get('<url>', function(response) { .. }); // Cache
Request.get('<url>', function(response) { .. }); // Cache

سيكون الحل البسيط للغاية هو جعل أول مكالمة AJAX متزامنة. إنها واحدة من المعلمات الاختيارية.

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