Since the release of ECMAScript's Promise ES2015 and async/await ES2017 features, asynchronous has become a particularly common operation in the front-end industry. There are some differences in the order in which asynchronous code and synchronous code handle problems. Writing asynchronous code requires a different "awareness" than writing synchronous code.
What happens if a piece of code cannot be executed for a long time?
If this is synchronous code, we will see a phenomenon called "unresponsive", or in layman's terms - "dead"; but what if it is a piece of asynchronous code? Maybe we can't wait for the result, but other codes are still continuing, as if this hasn't happened.
Of course, things didn't really happen, but different phenomena would occur under different circumstances. For example, if a page with an animation is loading, it seems that it is loading all the time; for example, if a page with data update is not visible, the data changes cannot be seen;
For example, a dialog box cannot be closed... These phenomena are collectively called bugs. But sometimes, a certain asynchronous operation process does not "echo", and it dies silently. No one knows that after the page is refreshed, even a trace will not be left behind.
Axios comes with timeout processing
Using Axios to make Web API calls is a common asynchronous operation process. Usually our code will be written like this:
try { const res = await (url, options); // TODO conducts follow-up services normally} catch(err) { // TODO performs fault-tolerant processing, or reports an error}
This code is generally executed well until one day the user complained: Why did you wait for a long time and didn’t respond?
The developer then realized that due to the increasing pressure on the server, it was difficult to respond instantly. Considering the user's feelings, a loading animation was added:
try { showLoading(); const res = await (url, options); // TODO Normal business} catch (err) { // TODO fault-tolerant processing} finally { hideLoading(); }
However, one day, a user said, "I waited for half an hour and was actually spinning around there!" So the developer realized that for some reason, the request was stuck. In this case, the request should be resent, or reported to the user directly - Well, a timeout check must be added.
Fortunately, Axios can indeed handle timeouts, just need tooptions
Add one totimeout: 3000
can solve the problem. If the timeout, you cancatch
Detect and process in blocks:
try {...} catch (err) { if ( && ! && && ("timeout")) { // If it is an Axios request error, and the message is a delay message // TODO processing timeout } } finally {...}
Axios is fine, if you use itfetch()
Woolen cloth?
Handling fetch() timeout
fetch()
I do not have the ability to handle timeouts, and we need to judge the timeout and passAbortController
to trigger the "cancel" request operation.
If one needs to be interruptedfetch()
Operation, just from oneAbortController
Object acquisitionsignal
, and use this signal object asfetch()
Options are passed in. It's probably like this:
const ac = new AbortController(); const { signal } = ac; fetch(url, { signal }).then(res => { // TODO handles business}); // Cancel the fetch operation after 1 secondsetTimeout(() => (), 1000);
()
Will tosignal
Send a signal and trigger itabort
Events and put them.aborted
Attribute settrue
。fetch()
Internal processing will use this information to abort the request.
The above example demonstrates how to implement itfetch()
Timeout processing of operation. If usedawait
To deal with it in the form of , it needs to besetTimeout(...)
Putfetch(...)
Before:
const ac = new AbortController(); const { signal } = ac; setTimeout(() => (), 1000); const res = await fetch(url, { signal }).catch(() => undefined);
To avoid usingtry ... catch ...
To handle the request failed, herefetch()
Added one later.catch(...)
Ignore the error situation. If an error occurs,res
Will be assigned asundefined
. The actual business processing may need to be more reasonablecatch()
Treat to letres
Contains identifiable error information.
It was already over here, but for everyfetch()
It will appear very cumbersome to write such a long piece of code. It is better to encapsulate it:
async function fetchWithTimeout(timeout, resoure, init = {}) { const ac = new AbortController(); const signal = ; setTimeout(() => (), timeout); return fetch(resoure, { ...init, signal }); }
Is there any problem? No, there is a problem.
If we are in the above codesetTimeout(...)
Output a message:
setTimeout(() => { ("It's timeout"); (); }, timeout);
And give enough time in the call:
fetchWithTimeout(5000, url).then(res => ("success"));
We will see the outputsuccess
, and see the output after 5 secondsIt's timeout
。
By the way, although wefetch(...)
The timeout was processed, but it was notfetch(...)
Kill it if successfultimer
. As a meticulous programmer, how can he make such a mistake? Kill him!
async function fetchWithTimeout(timeout, resoure, init = {}) { const ac = new AbortController(); const signal = ; const timer = setTimeout(() => { ("It's timeout"); return (); }, timeout); try { return await fetch(resoure, { ...init, signal }); } finally { clearTimeout(timer); } }
Perfect! But the problem is not over yet.
Everything can pass time
Axios and fetch both provide ways to interrupt asynchronous operations, but for one that does not haveabort
What should I do for ordinary Promises with abilities?
Regarding such a promise, I can only say, let him go, and he can do it forever - I can't stop it anyway. But life has to continue, I can’t wait forever!
In this case we cansetTimeout()
Encapsulate into a Promise and use()
To achieve "outdated":
race means racing, so()
Is the behavior easy to understand?
function waitWithTimeout(promise, timeout, timeoutMessage = "timeout") { let timer; const timeoutPromise = new Promise((_, reject) => { timer = setTimeout(() => reject(timeoutMessage), timeout); }); return ([timeoutPromise, promise]) .finally(() => clearTimeout(timer)); // Don't forget to clear timer}
You can write a Timeout to simulate the effect:
(async () => { const business = new Promise(resolve => setTimeout(resolve, 1000 * 10)); try { await waitWithTimeout(business, 1000); ("[Success]"); } catch (err) { ("[Error]", err); // [Error] timeout } })();
The above is the detailed content of the perfect solution to the asynchronous operation of JavaScript front-end timeout. For more information on solving the asynchronous operation of front-end timeout, please pay attention to my other related articles!