Condivisione della tecnologia

Come annullare la chiamata all'interfaccia sul front-end

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

🧑‍💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣

1. In che modo xmlHttpRequest annulla la richiesta?

Esiste anche un metodo di interruzione sull'oggetto XMLHttpRequest istanziato.

const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(e) {
  console.log(this.responseText);
});
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
xhr.send();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
// 返回
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Se interrotto subito dopo l'invio, annullare

// xhr的取消操作:执行过程比较模糊,不知道abort什么时机进行处理
xhr.abort()

  • 1
  • 2
  • 3

Se annulli la richiesta durante il timer (quando la durata del timer è simile alla durata della richiesta dell'interfaccia), scoprirai che la risorsa è stata ottenuta, ma non è presente alcuna stampa sulla console.
Inserisci qui la descrizione dell'immagine

2. Controllo interruzione

const ac = new AbortController();
const { signal } = ac;
const url = "https://jsonplaceholder.typicode.com/todos/1";
​
fetch(url, { signal })
  .then((res) => res.json())
  .then((json) => console.log(json));

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Utilizzare direttamente l'interruzione per annullare la richiesta

ac.abort()

  • 1
  • 2

Inserisci qui la descrizione dell'immagine
Il motivo dell'errore riportato qui è che l'errore non è stato acquisito.

// 修改后的代码
fetch(url, { signal: ac.signal })
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch(e => console.log(e)) // DOMException: signal is aborted without reason
ac.abort() // abort接受一个入参,会被传递到signal的reason属性中

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Perché è possibile cancellarlo in questo modo?

fetch monitora lo stato dell'oggetto signal e può terminare la richiesta

2.1 Come annullare più richieste contemporaneamente?

const ac = new AbortController();
const { signal } = ac;
const url = "https://jsonplaceholder.typicode.com/todos";
​
const todoRequest = (id, { signal }) => {
  fetch(`${url}/${id}`, { signal })
    .then((res) => res.json())
    .then((json) => console.log(json))
    .catch((e) => console.log(e)); // DOMException: signal is aborted without reason
};
​
todoRequest(1, { signal });
todoRequest(2, { signal });
todoRequest(3, { signal });
​
ac.abort("cancled");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Inserisci qui la descrizione dell'immagine

2.2 Segnale di interruzione

è un'interfaccia utilizzata per rappresentare un oggetto segnale che consente di comunicare con un'operazione asincrona in esecuzione in modo che l'operazione possa essere interrotta prima che venga completata.

2.3 Metodo AbortSignal

2.3.1 interruzione

Metodo statico utilizzato per creare un oggetto AbortSignal interrotto. Quando chiami questo metodo, restituisce un'istanza AbortSignal con stato interrotto pari a true.

const signalAbout = AbortSignal.abort(); // AbortSignal {aborted: true, reason: DOMException: signal is aborted without reason...}

  • 1
  • 2

2.3.2 Metodo ThrowIfAborted

Utilizzato per verificare se AbortSignal è stato interrotto prima di eseguire il codice. Se AbortSignal è stato interrotto, genererà un AbortError. Questo metodo può aiutare gli sviluppatori a garantire che non vengano interrotti prima di eseguire un'operazione specifica per evitare elaborazioni non necessarie.

const signalAbout = AbortSignal.abort('abortedReason');
try {
    signalAbout.throwIfAborted(); // 抛出error: abortedReason
} catch (error) {
    console.log(error);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.3.3 tempo scaduto

Utilizzato per creare un oggetto AbortSignal che termina automaticamente dopo un tempo specificato. Ciò è utile quando è necessario impostare un timeout della richiesta.

// 使用 AbortSignal.timeout 设置 10ms超时
const signalAbout = AbortSignal.timeout(10);
const todoRequest = (id, { signal }) => {
  fetch(`${url}/${id}`, { signal })
    .then((res) => res.json())
    .then((json) => console.log("json: ", json))
    .catch((e) => console.log("err: ", e)); //DOMException: signal timed out 
};
todoRequest(1, { signal: signalAbout });

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Inserisci qui la descrizione dell'immagine

2.3.3.1 Aggiungi listener di eventi => da non terminato a terminato

AbortSignal eredita da EventTarget, perché AbortSignal viene utilizzato per ascoltare gli eventi di interruzione e EventTarget fornisce un meccanismo per aggiungere, rimuovere e attivare i listener di eventi.

const signalAbout = AbortSignal.timeout(10);
signalAbout.addEventListener("abort", (e) => {
    console.log("aborted: ", e);
})
​

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

La stampa di e è la seguente:
Inserisci qui la descrizione dell'immagine

3. Implementare una promessa annullata in modo proattivo

const ac = new AbortController();
const { signal } = ac;
​
const cancelablePromise = ({signal}) => 
    new Promise((resolve, reject) => {
        // 情况1:直接主动取消
        signal?.throwIfAborted(); // 也可以用reject
​
        // 情况2:正常处理业务逻辑
​
        setTimeout(() => {
            Math.random() > 0.5 ? resolve('data') : reject('fetch error');
        }, 1000);
​
        // 情况3:超时 todo?
​
        // 监听取消
        signal.addEventListener("abort", () => {
            reject(signal?.reason);
        });
    })
// 发起网络请求
cancelablePromise({signal})
.then(res => console.log('res: ', res))
.catch(err => console.log('err: ', err))
// 情况1 
// ac.abort('用户离开页面了') // err:  用户离开页面了
​
// 情况2 正常请求 err:  fetch error || res:  data

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

4. Come utilizzare il segnale per annullare l'ascolto degli eventi?

Quando più ascoltatori di eventi vengono aggiunti a un elemento, non è necessario annullarlo come rimuoveEventListener. Ogni evento deve essere annullato una volta e l'handle dell'evento corrispondente deve essere scritto ogni volta.

Quando si utilizza il segnale, è necessario annullare il segnale solo una volta e tutto il monitoraggio degli eventi verrà annullato.

const ac = new AbortController();
const { signal } = ac;
const eleA = document.querySelector('#a');
const eleB = document.querySelector('#b');
​
function aEleHandler () {}; // 事件
eleA.addEventListener('click', aEleHandler, {signal}); // 无论绑定多少个事件,都只需要一个signal
​
eleB.addEventListener('click', () => {
    ac.abort(); // 只需要取消一次
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5. Scenari in cui sono richieste più interfacce per l'assemblaggio dei dati

Come annullare questa richiesta di rete continua quando la velocità della rete non è buona?

const ac = new AbortController();
const { signal } = ac;
const fetchAndRenderAction = (signal) => {
    requestData(signal); // 多个串行或者并行的接口
    drawAndRender(signal); // 异步渲染
}
​
try{
    fetchAndRenderAction({signal})
}catch{
    // dosomething...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

6. Riepilogo

Quando l'utente lascia attivamente la pagina o la rete dell'utente è molto bloccata (l'ordine di restituzione previsto è: interfaccia 1 => interfaccia 2; ma il ritorno dell'interfaccia 1 è troppo lento, causando confusione nell'ordine). Ciò richiede l'uso manuale cessazione della richiesta. Il segnale del semaforo di istanza del costruttore AbortController (può essere memorizzato come ref), signal viene utilizzato come parametro di fetch. Ad ogni richiesta, il metodo abort può essere chiamato manualmente per annullare la richiesta precedente.

Se ti è utile, sei invitato a prestare attenzione. Aggiornerò regolarmente la documentazione tecnica in modo che tutti possano discutere, imparare e fare progressi insieme.
Inserisci qui la descrizione dell'immagine