1
- /* eslint-env browser */
2
1
/* eslint-disable no-use-before-define */
3
2
4
- // This throttles and retries fetch() to mitigate the effect of random network errors and
3
+ const { scratchFetch} = require ( './scratchFetch' ) ;
4
+
5
+ // This throttles and retries scratchFetch() to mitigate the effect of random network errors and
5
6
// random browser errors (especially in Chrome)
6
7
7
8
let currentFetches = 0 ;
8
9
const queue = [ ] ;
9
10
11
+ const sleep = ms => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
12
+
10
13
const startNextFetch = ( [ resolve , url , options ] ) => {
11
14
let firstError ;
12
15
let failedAttempts = 0 ;
13
16
14
- const attemptToFetch = ( ) => fetch ( url , options )
15
- . then ( result => {
16
- // In a macOS WKWebView, requests from file: URLs to other file: URLs always have status: 0 and ok: false
17
- // even though the requests were successful. If the requested file doesn't exist, fetch() rejects instead.
18
- // We aren't aware of any other cases where fetch() can resolve with status 0, so this should be safe.
19
- if ( result . ok || result . status === 0 ) return result . arrayBuffer ( ) ;
20
- if ( result . status === 404 ) return null ;
21
- return Promise . reject ( result . status ) ;
22
- } )
23
- . then ( buffer => {
24
- currentFetches -- ;
25
- checkStartNextFetch ( ) ;
26
- return buffer ;
27
- } )
17
+ const done = result => {
18
+ currentFetches -- ;
19
+ checkStartNextFetch ( ) ;
20
+ resolve ( result ) ;
21
+ } ;
22
+
23
+ const attemptToFetch = ( ) => scratchFetch ( url , options )
24
+ . then ( done )
28
25
. catch ( error => {
29
- if ( error === 403 ) {
30
- // Retrying this request will not help, so return an error now.
31
- throw error ;
32
- }
26
+ // If fetch() errors, it means there was a network error of some sort.
27
+ // This is worth retrying, especially as some browser will randomly fail requests
28
+ // if we send too many at once (as we do).
33
29
34
30
console . warn ( `Attempt to fetch ${ url } failed` , error ) ;
35
31
if ( ! firstError ) {
@@ -38,16 +34,14 @@ const startNextFetch = ([resolve, url, options]) => {
38
34
39
35
if ( failedAttempts < 2 ) {
40
36
failedAttempts ++ ;
41
- return new Promise ( cb => setTimeout ( cb , ( failedAttempts + Math . random ( ) - 1 ) * 5000 ) )
42
- . then ( attemptToFetch ) ;
37
+ sleep ( ( failedAttempts + Math . random ( ) - 1 ) * 5000 ) . then ( attemptToFetch ) ;
38
+ return ;
43
39
}
44
40
45
- currentFetches -- ;
46
- checkStartNextFetch ( ) ;
47
- throw firstError ;
41
+ done ( Promise . reject ( firstError ) ) ;
48
42
} ) ;
49
43
50
- return resolve ( attemptToFetch ( ) ) ;
44
+ attemptToFetch ( ) ;
51
45
} ;
52
46
53
47
const checkStartNextFetch = ( ) => {
@@ -57,9 +51,9 @@ const checkStartNextFetch = () => {
57
51
}
58
52
} ;
59
53
60
- const saferFetchAsArrayBuffer = ( url , options ) => new Promise ( resolve => {
54
+ const saferFetch = ( url , options ) => new Promise ( resolve => {
61
55
queue . push ( [ resolve , url , options ] ) ;
62
56
checkStartNextFetch ( ) ;
63
57
} ) ;
64
58
65
- module . exports = saferFetchAsArrayBuffer ;
59
+ module . exports = saferFetch ;
0 commit comments