Bir HTTP getirme () isteğini nasıl iptal edebilirim?


Yanıtlar:


283

TL / DR:

fetchşu anda signal20 Eylül 2017 itibarıyla bir parametreyi destekliyor , ancak şu anda tüm tarayıcılar bunu desteklemiyor gibi görünüyor .

2020 GÜNCELLEME: Çoğu büyük tarayıcı (Edge, Firefox, Chrome, Safari, Opera ve diğerleri) DOM yaşam standardının bir parçası haline gelen özelliği desteklemektedir . (5 Mart 2020 itibariyle)

Bu, olsa çok yakında göreceğiz bir değişikliktir ve buna bağlı olarak bir kullanarak bir isteği iptal etmek gerekir AbortControllers AbortSignal.

Uzun versiyon

Nasıl:

Çalışma şekli şudur:

1. Adım : Bir oluşturmak AbortController(Şimdilik sadece kullanılan bu )

const controller = new AbortController()

Adım 2 : AbortControllerS sinyalini şu şekilde alırsınız :

const signal = controller.signal

Adım 3 : Getirmek için şu signalşekilde geçirin:

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

4. Adım : İhtiyacınız olduğunda iptal edin:

controller.abort();

İşte nasıl çalışacağına bir örnek (Firefox 57+ üzerinde çalışır):

<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>

Kaynaklar:


2
Bu cevap doğrudur ve kaldırılmalıdır. Ancak kod snippet'inde bazı düzenlemeler yapma özgürlüğünü aldım, çünkü olduğu gibi aslında Firefox 57 + 'da çalışmıyor - şim başarısız olmasına neden oluyor gibi görünüyordu ( “Err: TypeError:' sinyal 'RequestInit üyesi AbortSignal arabirimini uygulamaz. ” ) ve slowwly.robertomurray.co.uk için sertifika ile ilgili bir sorun var gibi görünüyor ( “ Bu sunucu slowwly.robertomurray.co.uk olduğunu kanıtlayamadı; güvenlik sertifikası * .herokuapp.com. ” ), bu yüzden sadece slowwly.robertomurray.co.uk (düz http) kullanacak şekilde değiştirdim .
sideshowbarker

3
Ancak şimdi Chrome gibi diğer tarayıcılarda çalışmaz AbortController is not defined. Her neyse, bu sadece bir kavram kanıtıdır, en azından Firefox 57+ olan insanlar çalıştığını görebilir
SudoPlz

3
Bu saf StackOverflow altın, özlü yazma için teşekkürler! Ve bugtracker da bağlanıyor!
Kjellski

3
Artık tüm modern tarayıcılar bunu destekliyor. developer.mozilla.org/tr-TR/docs/Web/API/AbortController/abort alttaki tabloya bakınız
Alex Ivasyuv

2
Teşekkürler ama hala bir sorum var, el ile bir sonraki getirme için sinyali tekrar true olarak değiştirmeli miyiz?
akshay kishore

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();

Edge 16 (2017-10-17), Firefox 57 (2017-11-14), Masaüstü Safari 11.1 (2018-03-29), iOS Safari 11.4 (2018-03-29), Chrome 67 (2018-05) -29) ve sonrası.


daha eski tarayıcılarda github'un whatwg -fetch çoklu dolgusunu ve AbortController çoklu dolgusunu kullanabilirsiniz . Eğer yapabilirsiniz eski tarayıcıları algılayıp şartlı polyfills kullanmak da:

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


@ FábioSantos Yorumunuz soru üzerine mi yoksa kendi başına bir cevap mı olmalı? Cevabıma özel görünmüyor.
Jayen

Github getirme çoklu dolgusunu kullanan insanlar için sadece bir not. Bunun cevabınızla ilgili olduğunu düşündüm çünkü AFAIK mevcut en popüler getirme poli dolgusu ve kullandığınız işlevi getirip getiriyor. Birçok kullanıcı eski tarayıcılar nedeniyle bu çoklu dolguyu kullanacak. İnsanların her şeyi düzelttiğini varsayarsak, ancak bu özel bir AbortController'ı çoklu doldurmaya çalışmadığından bahsetmeyi önemli buldum. AbortController'ı eski tarayıcılarda çoklu doldurulacağını düşünerek kullanmaya çalışıyorlardı ve boom, bir köşe durumunda ve sadece eski tarayıcılarda bir istisna var.
Fábio Santos

5

Şubat 2018'den fetch()itibaren Chrome'da aşağıdaki kodla iptal edilebilir ( Firefox desteğini etkinleştirmek için Okunabilir Akışları Kullanma bölümünü okuyun ). Almak için herhangi bir hata yapılmaz catch()ve bu AbortControllertamamen benimsenene kadar geçici bir çözümdür .

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
Bu OP istediğini DEĞİLDİR. Okuyucuyu değil getirmeyi iptal etmek istiyorlar. Getirme sözü, istek bittikten sonra, sunucuya isteği iptal etmek için çok geç olana kadar çözümlenmez.
Rahly

3

Şimdilik gelince, @spro'nun dediği gibi uygun bir çözüm yok.

Ancak, uçuş sırasında yanıtınız varsa ve ReadableStream kullanıyorsanız, isteği iptal etmek için akışı kapatabilirsiniz.

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

Çok dolgu yapalım:

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;
}

Lütfen kodun test edilmediğini unutmayın! Test ettiyseniz ve bir şey işe yaramadıysa bize bildirin. JavaScript resmi kitaplığından 'getir' işlevinin üzerine yazmaya çalıştığınız konusunda uyarılar verebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.