Berbagi teknologi

Cara membatalkan panggilan antarmuka di front end

2024-07-12

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

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

1. Bagaimana cara xmlHttpRequest membatalkan permintaan?

Ada juga metode pembatalan pada objek XMLHttpRequest yang dipakai.

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

Jika dibatalkan langsung setelah dikirim, batalkan

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

  • 1
  • 2
  • 3

Jika Anda membatalkan permintaan selama penghitung waktu (ketika durasi penghitung waktu mirip dengan durasi permintaan antarmuka), Anda akan menemukan bahwa sumber daya telah diperoleh, tetapi tidak ada cetakan di konsol.
Masukkan deskripsi gambar di sini

2. Kontroler Abort

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

Gunakan batalkan secara langsung untuk membatalkan permintaan

ac.abort()

  • 1
  • 2

Masukkan deskripsi gambar di sini
Alasan kesalahan yang dilaporkan di sini adalah karena kesalahan tersebut tidak terekam.

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

Kenapa bisa dibatalkan seperti ini?

ambil memonitor status objek sinyal dan dapat menghentikan permintaan

2.1 Bagaimana cara membatalkan beberapa permintaan sekaligus?

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

Masukkan deskripsi gambar di sini

2.2 Sinyal Batal

adalah antarmuka yang digunakan untuk mewakili objek sinyal yang memungkinkan Anda berkomunikasi dengan operasi asinkron yang sedang dilakukan sehingga operasi dapat dibatalkan sebelum selesai.

2.3 Metode Batalkan Sinyal

2.3.1 Batalkan

Metode statis yang digunakan untuk membuat objek AbortSignal yang dibatalkan. Saat Anda memanggil metode ini, metode ini mengembalikan instance AbortSignal dengan status true yang dibatalkan.

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

  • 1
  • 2

2.3.2 metode throwIfAborted

Digunakan untuk memeriksa apakah AbortSignal telah dibatalkan sebelum mengeksekusi kode. Jika AbortSignal telah dibatalkan, AbortError akan muncul. Metode ini dapat membantu pengembang memastikan bahwa mereka tidak dibatalkan sebelum melakukan operasi tertentu untuk menghindari pemrosesan yang tidak perlu.

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

Digunakan untuk membuat objek AbortSignal yang otomatis berakhir setelah waktu tertentu. Ini berguna ketika Anda perlu menetapkan batas waktu permintaan.

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

Masukkan deskripsi gambar di sini

2.3.3.1 Tambahkan event pendengar => dari tidak dihentikan ke dihentikan

AbortSignal mewarisi dari EventTarget, karena AbortSignal digunakan untuk mendengarkan peristiwa yang dibatalkan, dan EventTarget menyediakan mekanisme untuk menambah, menghapus, dan memicu pendengar peristiwa.

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

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

Pencetakan e adalah sebagai berikut:
Masukkan deskripsi gambar di sini

3. Melaksanakan janji yang dibatalkan secara proaktif

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. Bagaimana cara menggunakan sinyal untuk membatalkan acara mendengarkan?

Ketika beberapa event listening ditambahkan ke sebuah elemen, elemen tersebut tidak perlu dibatalkan seperti deleteEventListener. Setiap event perlu dibatalkan satu kali, dan event handle dari event terkait harus ditulis setiap saat.

Saat menggunakan sinyal, Anda hanya perlu membatalkan sinyal satu kali, dan semua pemantauan peristiwa akan dibatalkan.

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. Skenario di mana beberapa antarmuka diminta untuk perakitan data

Bagaimana cara membatalkan permintaan jaringan berkelanjutan ini ketika kecepatan jaringan tidak bagus?

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

Ketika pengguna aktif meninggalkan halaman, atau jaringan pengguna sangat macet (urutan pengembalian yang diharapkan adalah: antarmuka 1 => antarmuka 2; tetapi pengembalian antarmuka 1 terlalu lambat, menyebabkan urutannya menjadi bingung.) Ini memerlukan manual penghentian permintaan. Contoh sinyal semaphore dari konstruktor AbortController (dapat disimpan sebagai ref), sinyal digunakan sebagai parameter pengambilan. Pada setiap permintaan, metode pembatalan dapat dipanggil secara manual untuk membatalkan permintaan sebelumnya.

Jika bermanfaat bagi Anda, silakan memperhatikan. Saya akan memperbarui dokumentasi teknis secara berkala sehingga semua orang dapat berdiskusi, belajar, dan membuat kemajuan bersama.
Masukkan deskripsi gambar di sini