Today, when I was writing a front-end page, I realized that WHEN I needed to implement an associative function like Google search, I needed to manually terminate the request I made, such as:


Like input association

At this point, if the user keeps typing, if nothing is done it will result in a lot of requests for 1s, which is not reasonable. For example, if I type in the front end, if I don’t do any processing, the browser will make three requests, one for the front end, one for the front end, and each one will get the results and render them to the page, but in fact, we just need to get the results for the front end, At this time, I think it would be better to cancel the request for the last search word when the user input is detected, so I checked the relevant data. First of all, I used Fetch, so I found the relevant data on MDN, that is AbortController, the protagonist of today. Let’s look at the official Demo,

var controller = new AbortController(); var signal = controller.signal; var downloadBtn = document.querySelector('.download'); var abortBtn = document.querySelector('.abort'); downloadBtn.addEventListener('click', fetchVideo); abortBtn.addEventListener('click', function() { controller.abort(); console.log('Download aborted'); }); function fetchVideo() { ... fetch(url, {signal}).then(function(response) { ... }).catch(function(e) { reports.textContent = 'Download error: ' + e.message; })}Copy the code

Obviously, it is clear at a glance that Fetch can be terminated manually in this way. However, it is a pity that this technology is still under development as can be seen from MDN due to the common faults of the new front-end technology and browser support.


AbortController browser compatibility

It’s almost always supported by newer browsers.

Isn’t it a shame that such good technology can only be watched. However, we do not have to use the official specification, we can use a third-party module, such as Axios, on the github homepage of this project, you can see the use of cancellation, and you can check and use it yourself if you are interested.

This is followed by an implementation that I want to use Fetch only but can terminate manually because Fetch feels so refreshing 😂.

The idea is to repackage the asynchronous request and then use the setter to reject the asynchronous request.

Talk is cheap. Show me the code :

function wrap (func, ...args) {
    const cancel = {};
    return () => {
        const promiseHandle = new Promise((resolve, reject) => {
            Object.defineProperty(cancel, 'signal', {
                set () {
                    reject('Abort');
                }
            })

            func(...args).then(v => resolve(v)).catch(err => reject(err))
        });

        return Object.assign(promiseHandle, {
            cancel () {
                cancel.signal = true;
            }
        });
    }

}
Copy the code

It’s pretty crude, basically using the setter to call the encapsulated Promise and actively execute the Reject function in the setter.

Complete example:

function wrap (func, ... args) { const cancel = {}; return () => { const promiseHandle = new Promise((resolve, reject) => { Object.defineProperty(cancel, 'signal', { set () { reject('Abort'); } }) func(... args).then(v => resolve(v)).catch(err => reject(err)) }); return Object.assign(promiseHandle, { cancel () { cancel.signal = true; }}); } } var func = wrap((v) => new Promise((res, rej) => { setTimeout(() => res(v), 5000); }), 23333) var a = func() a.then(v => console.log(v)).catch(err => console.error(err)) a.cancel()Copy the code

Use result to be able to achieve expected behavior, if have wrong place, correct please, thank 🙏!