Teknologian jakaminen

Kuinka peruuttaa käyttöliittymäpuhelu käyttöliittymässä

2024-07-12

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

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

1. Miten xmlHttpRequest peruuttaa pyynnön?

Instantoidussa XMLHttpRequest-objektissa on myös keskeytysmenetelmä.

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

Jos keskeytät heti lähetyksen jälkeen, peruuta

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

  • 1
  • 2
  • 3

Jos peruutat pyynnön ajastimen aikana (kun ajastimen kesto on samanlainen kuin käyttöliittymäpyynnön kesto), huomaat, että resurssi on hankittu, mutta konsolissa ei ole tulostusta.
Lisää kuvan kuvaus tähän

2. AbortController

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

Peruuta pyyntö suoraan painamalla keskeytystä

ac.abort()

  • 1
  • 2

Lisää kuvan kuvaus tähän
Syy tähän raportoituun virheeseen on se, että virhettä ei saatu talteen.

// 修改后的代码
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

Miksi se voidaan peruuttaa näin?

fetch tarkkailee signaaliobjektin tilaa ja voi lopettaa pyynnön

2.1 Kuinka peruuttaa useita pyyntöjä samanaikaisesti?

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

Lisää kuvan kuvaus tähän

2.2 AbortSignal

on liitäntä, jota käytetään edustamaan signaaliobjektia, jonka avulla voit kommunikoida suoritettavan asynkronisen toiminnon kanssa, jotta toiminto voidaan keskeyttää ennen sen valmistumista.

2.3 AbortSignal-menetelmä

2.3.1 keskeyttää

Staattinen menetelmä, jota käytetään keskeytetyn AbortSignal-objektin luomiseen. Kun kutsut tätä menetelmää, se palauttaa AbortSignal-ilmentymän, jonka keskeytystila on tosi.

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

  • 1
  • 2

2.3.2 throwIfAborted -menetelmä

Käytetään tarkistamaan, onko AbortSignal keskeytetty ennen koodin suorittamista. Jos AbortSignal on keskeytetty, se antaa AbortError-ilmoituksen. Tämä menetelmä voi auttaa kehittäjiä varmistamaan, että niitä ei keskeytetä ennen tietyn toiminnon suorittamista tarpeettoman käsittelyn välttämiseksi.

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 aikakatkaisu

Käytetään luomaan AbortSignal-objekti, joka päättyy automaattisesti tietyn ajan kuluttua. Tämä on hyödyllistä, kun sinun on asetettava pyynnön aikakatkaisu.

// 使用 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

Lisää kuvan kuvaus tähän

2.3.3.1 Lisää tapahtuman kuuntelija => lopettamattomasta päättyneeseen

AbortSignal perii EventTargetista, koska AbortSignalia käytetään keskeytystapahtumien kuuntelemiseen, ja EventTarget tarjoaa mekanismin tapahtumakuuntelijoiden lisäämiseen, poistamiseen ja käynnistämiseen.

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

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

E:n tulostus on seuraava:
Lisää kuvan kuvaus tähän

3. Toteuta ennakoivasti peruutettu lupaus

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. Kuinka käyttää signaalia tapahtumien kuuntelun keskeyttämiseen?

Kun elementtiin lisätään useita tapahtumakuuntelijoita, sitä ei tarvitse peruuttaa, kuten removeEventListener. Jokainen tapahtuma on peruutettava kerran ja vastaavan tapahtuman tapahtumakahva on kirjoitettava joka kerta.

Signaalia käytettäessä sinun tarvitsee peruuttaa signaali vain kerran, jolloin kaikki tapahtumavalvonta peruuntuu.

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. Skenaariot, joissa tietojen kokoamiseen vaaditaan useita liitäntöjä

Kuinka peruuttaa tämä jatkuva verkkopyyntö, kun verkon nopeus ei ole hyvä?

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

Kun käyttäjä poistuu sivulta aktiivisesti tai käyttäjän verkko on hyvin jumissa (odotettu palautusjärjestys on: käyttöliittymä 1 => käyttöliittymä 2; mutta liitännän 1 paluu on liian hidasta, mikä aiheuttaa järjestyksen hämmennystä.) Tämä vaatii manuaalisen pyynnön lopettaminen. Konstruktorin AbortController instanssisemaforisignaali (voidaan tallentaa viitteenä), signaalia käytetään haun parametrina. Jokaisessa pyynnöstä keskeytysmenetelmä voidaan kutsua manuaalisesti peruuttamaan edellinen pyyntö.

Jos siitä on sinulle apua, olet tervetullut ottamaan huomioon, että päivitän teknistä dokumentaatiota säännöllisesti, jotta kaikki voivat keskustella, oppia ja edistyä yhdessä.
Lisää kuvan kuvaus tähän