Skip to content

Commit 13d4b8e

Browse files
2 parents 04f26d0 + a2e8372 commit 13d4b8e

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

FE-JS-Questions/Fetch-Retry.md

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
## JavaScript Fetch Retry (On failure)
2+
3+
> There are many cases, where network failure happens randomly. This affects the consistency of the results, especially in API calls. So, below is an implementation of `fetch-retry` function which retries `fetch` upon failure upto `n` times.
4+
5+
> Fetch (or axios library) works great for most AJAX requests in JavaScript. However, network fails happen randomly. To catch this issue, we will implement a function `fetch_retry(url, options, n)`, which does `fetch(url, options)` but retries it upto n times upon failure. This increases the chances of success and displaying consistent results.
6+
7+
### Approach 1: Loop over n times and call fetch
8+
```js
9+
function fetch_retry(url, options, n) {
10+
for (let i = 0; i < n; i++) {
11+
fetch(url, options);
12+
if (success) return result;
13+
}
14+
}
15+
```
16+
> Above approach will NOT work. Since FETCH is an asynchronous function, the program will not wait for the results before continuing. `n` fetches will be called at the same time, regardless of whether the previous calls succeed.
17+
18+
> `fetch` returns a Promise. So if when call succeeds, the function inside the `.then` will be called. And if the call fails, error will be caught in the `catch` block.
19+
20+
### fetch_retry outline
21+
```js
22+
function fetch_retry(url, options, n) {
23+
fetch(url, options)
24+
.then(function(result) {
25+
// on success
26+
}).catch(function(error) {
27+
// on failure
28+
});
29+
}
30+
```
31+
32+
> We will use a promise to make fetch_retry work synchronously. So `fetch_retry` will return a Promise, that resolves if any attempt out of n attempts succeed, and rejects if all `n` attempts succeed.
33+
```js
34+
function fetch_retry(url, options, n) {
35+
return new Promise(function(resolve, reject) {
36+
fetch(url, options)
37+
.then(function(result) {
38+
// on success
39+
}).catch(function(error) {
40+
// on failure
41+
})
42+
});
43+
}
44+
```
45+
46+
> If fetch succeeds, we can resolve the Promise returned by calling the resolve function.
47+
```js
48+
function fetch_retry(url, options, n) {
49+
return new Promise(function(resolve, reject) {
50+
fetch(url, options)
51+
.then(function(result) {
52+
// on success
53+
resolve(result); // Call resolve to resolve the returning promise
54+
}).catch(function(error) {
55+
// on failure
56+
})
57+
});
58+
}
59+
```
60+
61+
> If fetch fails, we call the fetch_retry function recursively, and reduce the the value of `n`
62+
```js
63+
function fetch_retry(url, options, n) {
64+
return new Promise(function(resolve, reject) {
65+
fetch(url, options)
66+
.then(function(result) {
67+
// on success
68+
resolve(result);
69+
}).catch(function(error) {
70+
// on failure
71+
fetch_retry(url, options, n - 1) // Call fetch_retry recursively
72+
.then(/* one of the remaining n - 1 calls to fetch will succeed */)
73+
.catch(/* remaining n - 1 fetch failed */)
74+
})
75+
});
76+
}
77+
```
78+
79+
> `fetch_retry` will return a Promise and resolve if any of the `n-1` attempts succeed and rejects if all the `n-1` attempts fail.
80+
81+
> If `fetch_retry` in the on failure case, succeeds, Promise will resolve, and reject if all the calls fail.
82+
```js
83+
function fetch_retry(url, options, n) {
84+
return new Promise(function(resolve, reject) {
85+
fetch(url, options)
86+
.then(function(result) {
87+
// on success
88+
resolve(result);
89+
}).catch(function(error) {
90+
// on failure
91+
fetch_retry(url, options, n - 1)
92+
.then(resolve) // Resolve
93+
.catch(reject); // Reject
94+
})
95+
});
96+
}
97+
```
98+
99+
> Since we have recursion involved, we need a base case to exit the function when all the fetch calls have failed `n` times. So if `n === 1` and fetch call fails, we reject with error from fetch, without calling fetch_retry any further
100+
```js
101+
function fetch_retry(url, options, n) {
102+
return new Promise(function(resolve, reject) {
103+
fetch(url, options)
104+
.then(function(result) {
105+
// on success
106+
resolve(result);
107+
}).catch(function(error) {
108+
if (n === 1) return reject(error);
109+
fetch_retry(url, options, n - 1)
110+
.then(resolve)
111+
.catch(reject);
112+
})
113+
});
114+
}
115+
```
116+
117+
> Since fetch itself returns a Promise, the `return Promise` part is redundant. Also we do not need to explicitly call resolve and reject on failure after `fetch_retry` is called in the catch section. So by cleaning up, we have below:
118+
```js
119+
function fetch_retry(url, options, n) {
120+
return fetch(url, options)
121+
.catch(function(error) {
122+
if (n === 1) throw error;
123+
return fetch_retry(url, options, n - 1);
124+
});
125+
}
126+
```
127+
128+
> Converting above to use arrow functions
129+
```js
130+
const fetch_retry = (url, options, n) => fetch(url, options).catch(error => {
131+
if (n === 1) throw error;
132+
return fetch_retry(url, options, n - 1);
133+
});
134+
```
135+
136+
> Using ES7 async await
137+
```js
138+
const fetch_retry = async (url, options, n) => {
139+
try {
140+
return await fetch(url, options);
141+
} catch(error) {
142+
if (n === 1) throw error;
143+
return await fetch_retry(url, options, n - 1);
144+
}
145+
};
146+
```
147+
148+
> async await without recursion
149+
```js
150+
const fetch_retry = async(url, options, n) => {
151+
let error;
152+
153+
for (let i = 0; i < n; i++) {
154+
try {
155+
return await fetch(url, options);
156+
} catch(err) {
157+
error = err;
158+
}
159+
}
160+
161+
throw error;
162+
}
163+
```
164+
165+
> Google Phone Interview question: Call an API, which is unstable in returning a response, and fails occassionally. So take the average of 3 successfull responses and return that as a result. However, if the entire process is not complete within 10 seconds, show an error message to the user.
166+
```js
167+
// Need to revisit
168+
const fetch_retry = async(url, options, n) => {
169+
let error;
170+
let result = [];
171+
let i = 0;
172+
173+
while (true) {
174+
try {
175+
if (i === n) {
176+
return result.reduce((acc, currentValue) => acc + currentValue, 0);
177+
}
178+
response = await fetch(url, options);
179+
result.push(response);
180+
i++;
181+
} catch(err) {
182+
error = err;
183+
}
184+
}
185+
186+
throw error;
187+
}
188+
let response = fetch_retry(url, options, 3);
189+
190+
setTimeout(function() {
191+
if (!response) {
192+
console.log("There was an error with the API");
193+
} else {
194+
console.log("Result is: ", response);
195+
}
196+
}, 10000)
197+
```

concepts/List.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class List {
2323
return;
2424
}
2525

26-
let lastAddress = this.memory[this.length - 1];
26+
let lastAddress = this.length - 1;
2727
const value = this.memory[lastAddress];
2828

2929
delete this.memory[lastAddress];

0 commit comments

Comments
 (0)