You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.3 KiB
138 lines
4.3 KiB
'use strict';
|
|
|
|
module.exports = function (fetch, defaults) {
|
|
defaults = defaults || {};
|
|
if (typeof fetch !== 'function') {
|
|
throw new ArgumentError('fetch must be a function');
|
|
}
|
|
|
|
if (typeof defaults !== 'object') {
|
|
throw new ArgumentError('defaults must be an object');
|
|
}
|
|
|
|
if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
|
|
throw new ArgumentError('retries must be a positive integer');
|
|
}
|
|
|
|
if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
|
|
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
|
|
}
|
|
|
|
if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
|
|
throw new ArgumentError('retryOn property expects an array or function');
|
|
}
|
|
|
|
var baseDefaults = {
|
|
retries: 3,
|
|
retryDelay: 1000,
|
|
retryOn: [],
|
|
};
|
|
|
|
defaults = Object.assign(baseDefaults, defaults);
|
|
|
|
return function fetchRetry(input, init) {
|
|
var retries = defaults.retries;
|
|
var retryDelay = defaults.retryDelay;
|
|
var retryOn = defaults.retryOn;
|
|
|
|
if (init && init.retries !== undefined) {
|
|
if (isPositiveInteger(init.retries)) {
|
|
retries = init.retries;
|
|
} else {
|
|
throw new ArgumentError('retries must be a positive integer');
|
|
}
|
|
}
|
|
|
|
if (init && init.retryDelay !== undefined) {
|
|
if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
|
|
retryDelay = init.retryDelay;
|
|
} else {
|
|
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
|
|
}
|
|
}
|
|
|
|
if (init && init.retryOn) {
|
|
if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
|
|
retryOn = init.retryOn;
|
|
} else {
|
|
throw new ArgumentError('retryOn property expects an array or function');
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line no-undef
|
|
return new Promise(function (resolve, reject) {
|
|
var wrappedFetch = function (attempt) {
|
|
fetch(input, init)
|
|
.then(function (response) {
|
|
if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
|
|
resolve(response);
|
|
} else if (typeof retryOn === 'function') {
|
|
try {
|
|
// eslint-disable-next-line no-undef
|
|
return Promise.resolve(retryOn(attempt, null, response))
|
|
.then(function (retryOnResponse) {
|
|
if(retryOnResponse) {
|
|
retry(attempt, null, response);
|
|
} else {
|
|
resolve(response);
|
|
}
|
|
}).catch(reject);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
} else {
|
|
if (attempt < retries) {
|
|
retry(attempt, null, response);
|
|
} else {
|
|
resolve(response);
|
|
}
|
|
}
|
|
})
|
|
.catch(function (error) {
|
|
if (typeof retryOn === 'function') {
|
|
try {
|
|
// eslint-disable-next-line no-undef
|
|
Promise.resolve(retryOn(attempt, error, null))
|
|
.then(function (retryOnResponse) {
|
|
if(retryOnResponse) {
|
|
retry(attempt, error, null);
|
|
} else {
|
|
reject(error);
|
|
}
|
|
})
|
|
.catch(function(error) {
|
|
reject(error);
|
|
});
|
|
} catch(error) {
|
|
reject(error);
|
|
}
|
|
} else if (attempt < retries) {
|
|
retry(attempt, error, null);
|
|
} else {
|
|
reject(error);
|
|
}
|
|
});
|
|
};
|
|
|
|
function retry(attempt, error, response) {
|
|
var delay = (typeof retryDelay === 'function') ?
|
|
retryDelay(attempt, error, response) : retryDelay;
|
|
setTimeout(function () {
|
|
wrappedFetch(++attempt);
|
|
}, delay);
|
|
}
|
|
|
|
wrappedFetch(0);
|
|
});
|
|
};
|
|
};
|
|
|
|
function isPositiveInteger(value) {
|
|
return Number.isInteger(value) && value >= 0;
|
|
}
|
|
|
|
function ArgumentError(message) {
|
|
this.name = 'ArgumentError';
|
|
this.message = message;
|
|
}
|