javascript - क्या jQuery के स्थगित को रद्द किया जा सकता है?




ajax jquery-deferred (3)

मेरे पास एक ऐसी स्थिति है जहां मैं एक आस्थगित को रद्द करना चाहता हूं। आस्थगित एक अजाक्स कॉल के साथ जुड़ा हुआ है।

क्यों मैं deferreds का उपयोग कर रहा हूँ

मैं $ .ajax द्वारा लौटी सामान्य xhr वस्तुओं का उपयोग नहीं करता। मैं jsonp का उपयोग कर रहा हूं, जिसका अर्थ है कि मैं त्रुटि से निपटने के लिए HTTP स्थिति कोड का उपयोग नहीं कर सकता और उन्हें प्रतिक्रियाओं में एम्बेड करना होगा। फिर कोड की जांच की जाती है और एक संबद्ध आस्थगित वस्तु को हल के रूप में चिह्नित या उसके अनुसार खारिज कर दिया जाता है। मेरे पास एक कस्टम एपीआई फ़ंक्शन है जो मेरे लिए ऐसा करता है।

function api(options) {
  var url = settings('api') + options.url;
  var deferred = $.Deferred(function(){
    this.done(options.success);
    this.fail(options.error);
  });
  $.ajax({
    'url': url,
    'dataType':'jsonp',
    'data': (options.noAuth == true) ? options.data : $.extend(true, getAPICredentials(), options.data)
  }).success(function(jsonReturn){
    // Success
    if(hasStatus(jsonReturn, 'code', 200)) {
      deferred.resolveWith(this, [jsonReturn]);
    } 
    // Failure
    else {
      deferred.rejectWith(this, [jsonReturn]);
    }
  });

  return deferred;
}

मैं क्यों स्थगित करना चाहता हूं

एक इनपुट फ़ील्ड है जो एक सूची के लिए एक फिल्टर के रूप में कार्य करता है और टाइपिंग समाप्त होने के बाद सूची को आधे सेकंड में स्वचालित रूप से अपडेट कर देगा। क्योंकि एक समय में दो अजाक्स कॉल बकाया होना संभव है, मुझे यह सुनिश्चित करने के लिए पिछली कॉल को रद्द करने की आवश्यकता है कि यह दूसरे के बाद वापस न आए और पुराना डेटा दिखाए।

समाधान मुझे पसंद नहीं है

  • मैं आस्थगित को अस्वीकार नहीं करना चाहता हूं क्योंकि यह .fail() साथ जुड़े हैंडलर को आग देगा।
  • मैं इसे अनदेखा नहीं कर सकता क्योंकि यह स्वचालित रूप से हल या अस्वीकार के रूप में चिह्नित किया जाएगा जब अजाक्स लौटता है।
  • आस्थगित हटाने से अज़ैक्स कॉल रिटर्न होने पर त्रुटि हो जाएगी और निराकृत या अस्वीकृत के रूप में आस्थगित को चिह्नित करने का प्रयास करेगा।

मुझे क्या करना चाहिए?

क्या आस्थगित को रद्द करने या किसी भी संलग्न हैंडलर को हटाने का एक तरीका है?

मेरे डिजाइन को कैसे ठीक किया जाए, इस पर सलाह का स्वागत है, लेकिन हैंडलर को हटाने या उन्हें रोकने के लिए रास्ता खोजने के लिए प्राथमिकता दी जाएगी।


JQuery के डॉक और कोड को देखते हुए, मुझे jQuery के आस्थगित को रद्द करने का कोई तरीका नहीं दिखता है।

इसके बजाय, आपको संभवतः अपने resolveWith हैंडलर में यह जानने की resolveWith है कि बाद में ajax कॉल को पहले ही निकाल दिया गया है और इस ajax कॉल को इसके परिणाम को अनदेखा करना चाहिए। आप विश्व स्तर पर वेतन वृद्धि काउंटर के साथ कर सकते हैं। आपके ajax कॉल के प्रारंभ में, आप काउंटर को बढ़ाते हैं और फिर आप मान को एक स्थानीय चर में पकड़ लेते हैं या इसे ajax ऑब्जेक्ट पर एक संपत्ति के रूप में डालते हैं। अपने resolveWith हैंडलर में, आप यह देखने के लिए जांचें कि क्या काउंटर में अभी भी वैसा ही मूल्य है जब आपके ajax कॉल की शुरुआत हुई थी। यदि नहीं, तो आप परिणाम की अनदेखी करते हैं। यदि ऐसा होता है, तो कोई भी नया अजाक्स कॉल नहीं किया गया है ताकि आप परिणाम को संसाधित कर सकें।

वैकल्पिक रूप से, आप एक नए अजाक्स कॉल को फायर करने से मना कर सकते हैं, जबकि एक पहले से ही उड़ान में है, इसलिए आपके पास एक समय में उड़ान में एक से अधिक कभी नहीं था। जब एक खत्म हो जाता है, तो आप या तो उस परिणाम का उपयोग कर सकते हैं या अगले एक को आग लगा सकते हैं।


जब आप चाहते हैं कि आप एक आस्थगित "रद्द" नहीं कर सकते हैं, तो आप $ a.jax के माध्यम से पिछले ajax कॉल का ट्रैक रखने के लिए एक सरल क्लोजर बना सकते हैं। ऐसा करने से आप बस कॉल कर सकते हैं () जब एक नया jqXHR खेलने के लिए आता है तो अंतिम एक समाप्त नहीं होता है। आपके कोड के मामले में यह jqXHR को अस्वीकार कर देगा और हटाए गए खुले को हटा दिया जाएगा जैसा कि आप शुरू में चाहते थे।

var api = (function() {
    var jqXHR = null;

    return function(options) {
        var url = options.url;

        if (jqXHR && jqXHR.state() === 'pending') {
            //Calls any error / fail callbacks of jqXHR
            jqXHR.abort();
        }

        var deferred = $.Deferred(function() {
            this.done(options.success);
            this.fail(options.error);
        });

        jqXHR = $.ajax({
             url: url,
             data: options.toSend,
             dataType: 'jsonp'
        });

        jqXHR.done(function(data, textStatus, jqXHR) {
            if (data.f && data.f !== "false") {
                deferred.resolve();
            } else {
                deferred.reject();
            }
        });

        //http://api.jquery.com/deferred.promise/  
        //keeps deferred's state from being changed outside this scope      
        return deferred.promise();
    };
})();

मैंने इसे jsfiddle पर पोस्ट किया है। यदि आप इसका परीक्षण करना चाहते हैं। सेट टाइमआउट का उपयोग jsfiddles delayer के संयोजन में किया जाता है ताकि किसी कॉल को इंटरप्ट किया जा सके। लॉग देखने के लिए आपको कंसोल सक्षम ब्राउज़र की आवश्यकता होगी।

एक साइड नोट पर किसी भी .success (), .error (), और पूर्ण () विधियों को किए गए स्थगित तरीकों पर स्विच करें (), विफल (), और हमेशा ()। वाया jquery/ajax

पदावनति सूचना: jqXHR.success (), jqXHR.error (), और jqXHR.complete () कॉलबैक jQuery 1.8 में पदावनत किए जाएंगे। उनके अंतिम निष्कासन के लिए अपना कोड तैयार करने के लिए, jqXHR.done (), jqXHR.fail (), और jqXHR.always () के बजाय नए का उपयोग करें


मैंने एक शिम बनाया है जो मूल रूप से आस्थगित वस्तुओं और अजाक्स अनुरोधों को रद्द करने की क्षमता जोड़ता है।

संक्षेप में, एक बार आस्थगित वस्तु को रद्द कर दिए जाने के बाद, प्रस्तावों / अस्वीकारों को पूरी तरह से नजरअंदाज कर दिया जाता है, और state "रद्द" हो जाता है।

JQuery.com के अनुसार, "एक बार जब ऑब्जेक्ट हल या अस्वीकृत स्थिति में प्रवेश कर जाता है, तो वह उस स्थिति में रहता है।" इसलिए, स्थगित ऑब्जेक्ट को हल या अस्वीकार करने के बाद रद्द करने के प्रयासों को अनदेखा किया जाता है।

(function () {
    originals = {
        deferred: $.Deferred,
        ajax: $.ajax
    };

    $.Deferred = function () {

        var dfr = originals.deferred(),
            cancel_dfr = originals.deferred();

        dfr.canceled = false;

        return {
            cancel: function () {
                if (dfr.state() == 'pending') {
                    dfr.canceled = true;
                    cancel_dfr.resolve.apply(this, arguments);
                }
                return this;
            },

            canceled: cancel_dfr.done,

            resolve: function () {
                if ( ! dfr.canceled) {
                    dfr.resolve.apply(dfr, arguments);
                    return this;
                }
            },

            resolveWith: function () {
                if ( ! dfr.canceled) {
                    dfr.resolveWith.apply(dfr, arguments);
                    return this;
                }
            },

            reject: function () {
                if ( ! dfr.canceled) {
                    dfr.reject.apply(dfr, arguments);
                    return this;
                }
            },

            rejectWith: function () {
                if ( ! dfr.canceled) {
                    dfr.rejectWith.apply(dfr, arguments);
                    return this;
                }
            },

            notify: function () {
                if ( ! dfr.canceled) {
                    dfr.notify.apply(dfr, arguments);
                    return this;
                }
            },

            notifyWith: function () {
                if ( ! dfr.canceled) {
                    dfr.notifyWith.apply(dfr, arguments);
                    return this;
                }
            },

            state: function () {
                if (dfr.canceled) {
                    return "canceled";
                } else {
                    return dfr.state();
                }
            },

            always   : dfr.always,
            then     : dfr.then,
            promise  : dfr.promise,
            pipe     : dfr.pipe,
            done     : dfr.done,
            fail     : dfr.fail,
            progress : dfr.progress
        };
    };


    $.ajax = function () {

        var dfr = $.Deferred(),
            ajax_call = originals.ajax.apply(this, arguments)
                .done(dfr.resolve)
                .fail(dfr.reject),

            newAjax = {},

            ajax_keys = [
                "getResponseHeader",
                "getAllResponseHeaders",
                "setRequestHeader",
                "overrideMimeType",
                "statusCode",
                "abort"
            ],

            dfr_keys = [
                "always",
                "pipe",
                "progress",
                "then",
                "cancel",
                "state",
                "fail",
                "promise",
                "done",
                "canceled"
            ];

        _.forEach(ajax_keys, function (key) {
            newAjax[key] = ajax_call[key];
        });

        _.forEach(dfr_keys, function (key) {
            newAjax[key] = dfr[key];
        });

        newAjax.success = dfr.done;
        newAjax.error = dfr.fail;
        newAjax.complete = dfr.always;

        Object.defineProperty(newAjax, 'readyState', {
            enumerable: true,
            get: function () {
                return ajax_call.readyState;
            },
            set: function (val) {
                ajax_call.readyState = val;
            }
        });

        Object.defineProperty(newAjax, 'status', {
            enumerable: true,
            get: function () {
                return ajax_call.status;
            },
            set: function (val) {
                ajax_call.status = val;
            }
        });

        Object.defineProperty(newAjax, 'statusText', {
            enumerable: true,
            get: function () {
                return ajax_call.statusText;
            },
            set: function (val) {
                ajax_call.statusText = val;
            }
        });

        // canceling an ajax request should also abort the call
        newAjax.canceled(ajax_call.abort);

        return newAjax;
    };
});

एक बार जोड़ने के बाद, आप एक अजाक्स कॉल रद्द कर सकते हैं:

var a = $.ajax({
        url: '//example.com/service/'
    });

a.cancel('the request was canceled');

// Now, any resolutions or rejections are ignored, and the network request is dropped.

.. और एक साधारण आस्थगित वस्तु:

var dfr = $.Deferred();

dfr
    .done(function () {
        console.log('Done!');
    })
    .fail(function () {
        console.log('Nope!');
    });

dfr.cancel(); // Now, the lines below are ignored. No console logs will appear.

dfr.resolve();
dfr.reject();




cancellation