javascript - वादा-क्या यह एक वादा रद्द करने के लिए मजबूर करना संभव है




promise cancellation (5)

मैं अपने सभी नेटवर्क डेटा पुनर्प्राप्ति का प्रबंधन करने के लिए ES6 वादों का उपयोग करता हूं और कुछ परिस्थितियां हैं जहां मुझे उन्हें रद्द करने के लिए मजबूर करने की आवश्यकता है।

मूल रूप से परिदृश्य ऐसा है कि मेरे पास यूआई पर एक टाइप-फॉरवर्ड खोज है जहां अनुरोध बैकेंड को सौंपा गया है और आंशिक इनपुट के आधार पर खोज को पूरा करना है। हालांकि इस नेटवर्क अनुरोध (# 1) में थोड़ा समय लग सकता है, उपयोगकर्ता टाइप करना जारी रखता है जो अंततः एक अन्य बैकेंड कॉल (# 2) को ट्रिगर करता है

यहां # 2 स्वाभाविक रूप से # 1 से अधिक पूर्वता लेता है, इसलिए मैं # 1 रैपिंग अनुरोध को रद्द करना चाहूंगा। मेरे पास डेटा लेयर में पहले से ही सभी वादों का कैश है, इसलिए मैं सैद्धांतिक रूप से इसे पुनः प्राप्त कर सकता हूं क्योंकि मैं # 2 के लिए एक प्रॉमिस सबमिट करने का प्रयास कर रहा हूं।

लेकिन कैश से पुनर्प्राप्त करने के बाद मैं # 1 वादा कैसे रद्द करूं?

क्या कोई दृष्टिकोण सुझा सकता है?


नहीं, हम अभी तक ऐसा नहीं कर सकते।

ES6 वादे रद्द करने का समर्थन नहीं करते हैं। यह अपने रास्ते पर है, और इसका डिज़ाइन कुछ ऐसा है जिस पर बहुत से लोगों ने वास्तव में कड़ी मेहनत की है। ध्वनि निरस्तीकरण शब्दार्थ सही पाने के लिए कठिन हैं और यह कार्य प्रगति पर है। जीएच पर "भ्रूण" रेपो, एस्किस्कस और कई अन्य रिपोज पर दिलचस्प बहसें हैं, लेकिन अगर मैं आप होता तो मैं धैर्य रखता।

लेकिन, लेकिन, लेकिन .. रद्द करना वास्तव में महत्वपूर्ण है!

यह है, मामले की वास्तविकता रद्द करना क्लाइंट-साइड प्रोग्रामिंग में वास्तव में एक महत्वपूर्ण परिदृश्य है। आपके द्वारा वेब अनुरोधों को निरस्त करने जैसे मामले महत्वपूर्ण हैं और वे हर जगह हैं।

तो ... भाषा ने मुझे डरा दिया!

हाँ, इसके बारे में क्षमा करें। .finally को आगे की चीजें निर्दिष्ट करने से पहले पहले प्राप्त करना था - इसलिए वे कुछ उपयोगी सामानों जैसे कि .finally और .cancel - के अंदर गए, हालांकि यह डोम के माध्यम से कल्पना पर है। रद्दीकरण एक बाद की बाधा नहीं है और एपीआई डिजाइन के लिए एक अधिक पुनरावृत्ति दृष्टिकोण है।

तो मै क्या कर सकता हूँ?

आपके पास कई विकल्प हैं:

  • bluebird जैसी थर्ड पार्टी लाइब्रेरी का उपयोग करें, जो कल्पना से बहुत तेज गति से आगे बढ़ सकता है और इस तरह से कैंसिलेशन के साथ-साथ अन्य अच्छाइयों का एक गुच्छा है - यही व्हाट्सएप जैसी बड़ी कंपनियां करती हैं।
  • रद्दीकरण टोकन पास करें।

थर्ड पार्टी लाइब्रेरी का उपयोग करना बहुत स्पष्ट है। टोकन के लिए, आप अपने तरीके से एक फंक्शन ले सकते हैं और फिर उसे कॉल कर सकते हैं, जैसे:

function getWithCancel(url, token) { // the token is for cancellation
   var xhr = new XMLHttpRequest;
   xhr.open("GET", url);
   return new Promise(function(resolve, reject) {
      xhr.onload = function() { resolve(xhr.responseText); });
      token.cancel = function() {  // SPECIFY CANCELLATION
          xhr.abort(); // abort request
          reject(new Error("Cancelled")); // reject the promise
      };
      xhr.onerror = reject;
   });
};

जो आपको करने देगा:

var token = {};
var promise = getWithCancel("/someUrl", token);

// later we want to abort the promise:
token.cancel();

आपका वास्तविक उपयोग मामला - last

यह टोकन दृष्टिकोण के साथ बहुत कठिन नहीं है:

function last(fn) {
    var lastToken = { cancel: function(){} }; // start with no op
    return function() {
        lastToken.cancel();
        var args = Array.prototype.slice.call(arguments);
        args.push(lastToken);
        return fn.apply(this, args);
    };
}

जो आपको करने देगा:

var synced = last(getWithCancel);
synced("/url1?q=a"); // this will get canceled 
synced("/url1?q=ab"); // this will get canceled too
synced("/url1?q=abc");  // this will get canceled too
synced("/url1?q=abcd").then(function() {
    // only this will run
});

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


Node.js और इलेक्ट्रॉन के लिए, मैं अत्यधिक जावास्क्रिप्ट (Prex) के लिए प्रॉमिस एक्सटेंशन्स का उपयोग करने की सलाह दूंगा । इसके लेखक रॉन बक्टन प्रमुख टाइपस्क्रिप्ट इंजीनियरों में से एक हैं और वर्तमान TC39 के ECMAScript रद्द करने के प्रस्ताव के पीछे भी आदमी है। पुस्तकालय अच्छी तरह से प्रलेखित है और संभावना है कि कुछ प्रॉक्स मानक के अनुरूप होंगे।

एक व्यक्तिगत नोट पर और एक भारी C # पृष्ठभूमि से आने पर, मुझे यह तथ्य बहुत पसंद है कि Prex को Managed Threads फ्रेमवर्क में मौजूदा रद्दीकरण पर आधारित किया गया है, अर्थात, CancellationTokenSource करने के लिए दृष्टिकोण के आधार पर लिया गया है। मेरे अनुभव में, प्रबंधित ऐप्स में मजबूत रद्दीकरण तर्क को लागू करने के लिए वे बहुत आसान हैं।

मैंने यह भी सत्यापित किया कि ब्राउजर का उपयोग करके Prex को बंडल करके एक ब्राउज़र के भीतर काम किया जाए

यहाँ रद्द करने के साथ देरी का एक उदाहरण है, prex.CancellationTokenSource का उपयोग करते prex.CancellationTokenSource :

const prex = require('prex');

async function delayWithCancellation(timeoutMs, token) {
  // this can easily be done without async/await,
  // but I believe this linear structure is more readable
  let reg = null;
  try {
    await new Promise((resolve, reject) => {
      const id = setTimeout(resolve, timeoutMs);
      reg = token.register(() => {
        clearTimeout(id);
        reject(new prex.CancelError("delay cancelled."));
      });
    });  
  }
  finally {
    reg && reg.unregister();
  }
}

async function main() {
  const tokenSource = new prex.CancellationTokenSource();
  setTimeout(() => tokenSource.cancel(), 1500); // cancel after 1500ms

  // without cancellation
  await delayWithCancellation(1000, prex.CancellationToken.none);
  console.log("successfully delayed once.");

  // with cancellation
  const token = tokenSource.token;
  await delayWithCancellation(1500, token);
  token.throwIfCancellationRequested();
  console.log("successfully delayed twice."); // we should not be here
}

main().catch(e => console.log(e));

ध्यान दें कि रद्दीकरण एक दौड़ है। Ie, एक वादा सफलतापूर्वक हल किया जा सकता है, लेकिन जब तक आप इसे ( await या then ) निरीक्षण करते हैं, then तक रद्द भी ट्रिगर हो सकता है। यह आपके ऊपर है कि आप इस दौड़ को कैसे संभालते हैं, लेकिन यह token.throwIfCancellationRequested() अतिरिक्त समय पर कॉल करने के लिए दर्द नहीं करता है, जैसे मैं ऊपर करता हूं।


मुझे हाल ही में इसी तरह की समस्या का सामना करना पड़ा।

मेरे पास एक वादा आधारित ग्राहक था (एक नेटवर्क नहीं) और मैं हमेशा यूआई को सुचारू रखने के लिए उपयोगकर्ता को नवीनतम अनुरोधित डेटा देना चाहता था।

रद्द करने के विचार के साथ संघर्ष करने के बाद, Promise.race(...) और Promise.all(..) मैंने अभी अपना आखिरी अनुरोध आईडी याद करना शुरू किया और जब वादा पूरा हुआ तो मैं केवल अपने डेटा का प्रतिपादन कर रहा था जब उसने अंतिम अनुरोध की आईडी से मिलान किया। ।

आशा है कि यह किसी की मदद करता है।


मैंने मोज़िला जेएस संदर्भ की जाँच की है और यह पाया है:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race

चलो पता करते हैं:

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});

हमारे पास यहाँ p1 है, और P2 को वाद-विवाद के रूप में Promise.race(...) में रखा गया है, यह वास्तव में नए संकल्प का वादा कर रहा है, जो आपको आवश्यक है।






cancellation