UNPKG

react-query

Version:

Hooks for managing, caching and syncing asynchronous and remote data in React

151 lines (122 loc) 4.42 kB
import { focusManager } from './focusManager'; import { onlineManager } from './onlineManager'; import { sleep } from './utils'; // TYPES function defaultRetryDelay(failureCount) { return Math.min(1000 * Math.pow(2, failureCount), 30000); } export function isCancelable(value) { return typeof (value == null ? void 0 : value.cancel) === 'function'; } export var CancelledError = function CancelledError(options) { this.revert = options == null ? void 0 : options.revert; this.silent = options == null ? void 0 : options.silent; }; export function isCancelledError(value) { return value instanceof CancelledError; } // CLASS export var Retryer = function Retryer(config) { var _this = this; var cancelRetry = false; var cancelFn; var continueFn; var promiseResolve; var promiseReject; this.cancel = function (cancelOptions) { return cancelFn == null ? void 0 : cancelFn(cancelOptions); }; this.cancelRetry = function () { cancelRetry = true; }; this.continue = function () { return continueFn == null ? void 0 : continueFn(); }; this.failureCount = 0; this.isPaused = false; this.isResolved = false; this.isTransportCancelable = false; this.promise = new Promise(function (outerResolve, outerReject) { promiseResolve = outerResolve; promiseReject = outerReject; }); var resolve = function resolve(value) { if (!_this.isResolved) { _this.isResolved = true; config.onSuccess == null ? void 0 : config.onSuccess(value); continueFn == null ? void 0 : continueFn(); promiseResolve(value); } }; var reject = function reject(value) { if (!_this.isResolved) { _this.isResolved = true; config.onError == null ? void 0 : config.onError(value); continueFn == null ? void 0 : continueFn(); promiseReject(value); } }; var pause = function pause() { return new Promise(function (continueResolve) { continueFn = continueResolve; _this.isPaused = true; config.onPause == null ? void 0 : config.onPause(); }).then(function () { continueFn = undefined; _this.isPaused = false; config.onContinue == null ? void 0 : config.onContinue(); }); }; // Create loop function var run = function run() { // Do nothing if already resolved if (_this.isResolved) { return; } var promiseOrValue; // Execute query try { promiseOrValue = config.fn(); } catch (error) { promiseOrValue = Promise.reject(error); } // Create callback to cancel this fetch cancelFn = function cancelFn(cancelOptions) { if (!_this.isResolved) { reject(new CancelledError(cancelOptions)); // Cancel transport if supported if (isCancelable(promiseOrValue)) { try { promiseOrValue.cancel(); } catch (_unused) {} } } }; // Check if the transport layer support cancellation _this.isTransportCancelable = isCancelable(promiseOrValue); Promise.resolve(promiseOrValue).then(resolve).catch(function (error) { var _config$retry, _config$retryDelay; // Stop if the fetch is already resolved if (_this.isResolved) { return; } // Do we need to retry the request? var retry = (_config$retry = config.retry) != null ? _config$retry : 3; var retryDelay = (_config$retryDelay = config.retryDelay) != null ? _config$retryDelay : defaultRetryDelay; var delay = typeof retryDelay === 'function' ? retryDelay(_this.failureCount, error) : retryDelay; var shouldRetry = retry === true || typeof retry === 'number' && _this.failureCount < retry || typeof retry === 'function' && retry(_this.failureCount, error); if (cancelRetry || !shouldRetry) { // We are done if the query does not need to be retried reject(error); return; } _this.failureCount++; // Notify on fail config.onFail == null ? void 0 : config.onFail(_this.failureCount, error); // Delay sleep(delay) // Pause if the document is not visible or when the device is offline .then(function () { if (!focusManager.isFocused() || !onlineManager.isOnline()) { return pause(); } }).then(function () { if (cancelRetry) { reject(error); } else { run(); } }); }); }; // Start loop run(); };