मैं एक HTTP लाने () अनुरोध को कैसे रद्द करूं?


202

जावास्क्रिप्ट से अनुरोध करने के लिए एक नया एपीआई है: fetch ()। क्या इन अनुरोधों को इन-फ्लाइट रद्द करने के लिए कोई तंत्र निर्मित है?


davidwalsh.name/cancel-fetch को भी संदर्भित कर सकते हैं
गणेश फिर्के

जवाबों:


283

टीएल / डॉ:

fetchअब signal20 सितंबर 2017 तक एक पैरामीटर का समर्थन करता है , लेकिन सभी ब्राउज़र फिलहाल इसका समर्थन नहीं करते हैं

2020 अद्यतन: अधिकांश प्रमुख ब्राउज़र (एज, फ़ायरफ़ॉक्स, क्रोम, सफारी, ओपेरा, और कुछ अन्य) इस सुविधा का समर्थन करते हैं , जो डोम के जीवन स्तर का हिस्सा बन गया है । (5 मार्च 2020 तक)

यह एक बदलाव है जो हम बहुत जल्द ही देखेंगे, और इसलिए आपको AbortControllerएस का उपयोग करके अनुरोध को रद्द करने में सक्षम होना चाहिए AbortSignal

दीर्घ संस्करण

कैसे:

जिस तरह से यह काम करता है वह यह है:

चरण 1 : आप एक बनाते हैं AbortController(अभी के लिए मैंने इसका इस्तेमाल किया था )

const controller = new AbortController()

चरण 2 : आपको AbortControllerइस तरह का संकेत मिलता है :

const signal = controller.signal

चरण 3 : आप इस signalतरह लाने के लिए पास :

fetch(urlToFetch, {
    method: 'get',
    signal: signal, // <------ This is our AbortSignal
})

चरण 4 : जब भी आपको आवश्यकता हो तो बस गर्भपात करें:

controller.abort();

यहां बताया गया है कि यह कैसे काम करेगा (फ़ायरफ़ॉक्स 57+ पर काम करता है):

<script>
    // Create an instance.
    const controller = new AbortController()
    const signal = controller.signal

    /*
    // Register a listenr.
    signal.addEventListener("abort", () => {
        console.log("aborted!")
    })
    */


    function beginFetching() {
        console.log('Now fetching');
        var urlToFetch = "https://httpbin.org/delay/3";

        fetch(urlToFetch, {
                method: 'get',
                signal: signal,
            })
            .then(function(response) {
                console.log(`Fetch complete. (Not aborted)`);
            }).catch(function(err) {
                console.error(` Err: ${err}`);
            });
    }


    function abortFetching() {
        console.log('Now aborting');
        // Abort.
        controller.abort()
    }

</script>



<h1>Example of fetch abort</h1>
<hr>
<button onclick="beginFetching();">
    Begin
</button>
<button onclick="abortFetching();">
    Abort
</button>

सूत्रों का कहना है:

  • DOM स्पेसिफिकेशन में AbortController का अंतिम संस्करण जोड़ा गया है
  • इसी पीआर लाने विनिर्देश अभी विलय कर दिया है।
  • AbortController के कार्यान्वयन पर नज़र रखने वाले ब्राउज़र बग यहां उपलब्ध हैं: फ़ायरफ़ॉक्स: # 1378342 , क्रोमियम: # 750599 , वेबिट : # 174980 , एज: # 13009916

2
यह उत्तर सही है और इसे अपग्रेड किया जाना चाहिए। लेकिन मैंने कोड स्निपेट में कुछ संपादन करने की स्वतंत्रता ले ली, क्योंकि जैसा कि यह वास्तव में फ़ायरफ़ॉक्स 57+ में काम नहीं कर रहा था - शिम लग रहा था कि यह विफल हो रहा है ( "त्रुटि: टाइपर: 'सिग्नल' अनुरोध के सदस्य इंटरफ़ेस AbortSignal को लागू नहीं करता है। " ) और slowwly.robertomurray.co.uk के लिए प्रमाण पत्र के साथ कुछ समस्या प्रतीत होती है ( " यह सर्वर साबित नहीं कर सका कि यह slowwly.robertomurray.co.uk है; इसका सुरक्षा प्रमाणपत्र * से है] .herokuapp.com। ” ), इसलिए मैंने इसे केवल धीमे-धीमे उपयोग करने के लिए बदल दिया ।robertomurray.co.uk (सादा http)।
sideshowbarker

3
लेकिन अब यह अन्य ब्राउज़रों यानी क्रोम पर काम नहीं करता है क्योंकि AbortController is not defined। वैसे भी यह केवल अवधारणा का प्रमाण है, कम से कम फ़ायरफ़ॉक्स 57+ वाले लोग इसे काम करते हुए देख सकते हैं
सूडोप्ल्ज़

3
यह शुद्ध स्टैकऑवरफ्लो गोल्ड है, संक्षिप्त राइटअप के लिए धन्यवाद! और बगट्रैकर लिंक भी!
केजेल्स्की

3
अब सभी आधुनिक ब्राउज़र इसका समर्थन करते हैं। डेवलपर.
mozilla.org/en-US/docs/Web/API/AbortController/abort

2
धन्यवाद, लेकिन मेरे पास अभी भी एक सवाल है, क्या हमें अगले भ्रूण के लिए मैन्युअल रूप से सिग्नल को सही में बदलना चाहिए ??
अक्षय किशोर

20

https://developers.google.com/web/updates/2017/09/abortable-fetch

https://dom.spec.whatwg.org/#aborting-ongoing-activities

// setup AbortController
const controller = new AbortController();
// signal to pass to fetch
const signal = controller.signal;

// fetch as usual
fetch(url, { signal }).then(response => {
  ...
}).catch(e => {
  // catch the abort if you like
  if (e.name === 'AbortError') {
    ...
  }
});

// when you want to abort
controller.abort();

एज 16 (2017-10-17), फ़ायरफ़ॉक्स 57 (2017-11-14), डेस्कटॉप सफारी 11.1 (2018-03-29), आईओएस सफारी 11.4 (2018-03-29), क्रोम 67 (2018-05) में काम करता है -29), और बाद में।


पुराने ब्राउज़रों पर, आप जीथब के व्हाट्स- गॉग पॉलीफिल और एबोर्टकंट्रोलर पॉलीफिल का उपयोग कर सकते हैं । आप पुराने ब्राउज़रों का पता लगा सकते हैं और पॉलीफ़िल का उपयोग सशर्त रूप से भी कर सकते हैं:

import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import {fetch} from 'whatwg-fetch'

// use native browser implementation if it supports aborting
const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch

यदि गीथब की पॉलीफिल का उपयोग किया जाता है, तो इसके साथ ऐसा करना संभव है, बस उनके रीडमी के निर्देशों का पालन करें: github.com/github/fetch#aborting-requests
Fábio Santos

@ FábioSantos आपकी टिप्पणी सवाल पर होनी चाहिए, या यह अपने आप में एक जवाब के रूप में है? यह मेरे उत्तर के लिए विशिष्ट नहीं है।
Jayen

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

5

फरवरी 2018 तक, fetch()क्रोम पर नीचे दिए गए कोड के साथ रद्द किया जा सकता है ( फ़ायरफ़ॉक्स समर्थन को सक्षम करने के लिए पठनीय धाराओं का उपयोग करके पढ़ें )। किसी भी त्रुटि catch()को लेने के लिए नहीं फेंका जाता है , और यह एक अस्थायी समाधान है जब तक AbortControllerकि पूरी तरह से अपनाया नहीं जाता है।

fetch('YOUR_CUSTOM_URL')
.then(response => {
  if (!response.body) {
    console.warn("ReadableStream is not yet supported in this browser.  See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream")
    return response;
  }

  // get reference to ReadableStream so we can cancel/abort this fetch request.
  const responseReader = response.body.getReader();
  startAbortSimulation(responseReader);

  // Return a new Response object that implements a custom reader.
  return new Response(new ReadableStream(new ReadableStreamConfig(responseReader)));
})
.then(response => response.blob())
.then(data => console.log('Download ended. Bytes downloaded:', data.size))
.catch(error => console.error('Error during fetch()', error))


// Here's an example of how to abort request once fetch() starts
function startAbortSimulation(responseReader) {
  // abort fetch() after 50ms
  setTimeout(function() {
    console.log('aborting fetch()...');
    responseReader.cancel()
    .then(function() {
      console.log('fetch() aborted');
    })
  },50)
}


// ReadableStream constructor requires custom implementation of start() method
function ReadableStreamConfig(reader) {
  return {
    start(controller) {
      read();
      function read() {
        reader.read().then(({done,value}) => {
          if (done) {
            controller.close();
            return;
          }
          controller.enqueue(value);
          read();
        })
      }
    }
  }
}

2
यह वह नहीं है जो ओपी पूछ रहा था। वे पाठक को नहीं लाने के लिए रद्द करना चाहते हैं। फ़िच का वादा तब तक हल नहीं होता है जब तक कि अनुरोध समाप्त नहीं हो जाता है, जो सर्वर के अनुरोध को रद्द करने के लिए बहुत देर हो चुकी है।
राहली

3

जैसा कि अभी तक कोई उचित समाधान नहीं है, जैसा कि @spro कहते हैं।

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

fetch('http://example.com').then((res) => {
  const reader = res.body.getReader();

  /*
   * Your code for reading streams goes here
   */

  // To abort/cancel HTTP request...
  reader.cancel();
});

0

चलो पॉलीफिल:

if(!AbortController){
  class AbortController {
    constructor() {
      this.aborted = false;
      this.signal = this.signal.bind(this);
    }
    signal(abortFn, scope) {
      if (this.aborted) {
        abortFn.apply(scope, { name: 'AbortError' });
        this.aborted = false;
      } else {
        this.abortFn = abortFn.bind(scope);
      }
    }
    abort() {
      if (this.abortFn) {
        this.abortFn({ reason: 'canceled' });
        this.aborted = false;
      } else {
        this.aborted = true;
      }
    }
  }

  const originalFetch = window.fetch;

  const customFetch = (url, options) => {
    const { signal } = options || {};

    return new Promise((resolve, reject) => {
      if (signal) {
        signal(reject, this);
      }
      originalFetch(url, options)
        .then(resolve)
        .catch(reject);
    });
  };

  window.fetch = customFetch;
}

कृपया ध्यान रखें कि कोड का परीक्षण नहीं किया गया है! मुझे पता है अगर आप इसे परीक्षण किया है और कुछ काम नहीं किया। यह आपको चेतावनियाँ दे सकता है कि आप जावास्क्रिप्ट आधिकारिक लाइब्रेरी से '' फंक्शन 'को अधिलेखित करने का प्रयास करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.