commit 167ba25c4f265c57a2846cb7f0045b2c0f9afc8f
parent 06289c3790bd0fdddb4566e69c5fc135c1fe2a93
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Tue, 29 Nov 2016 01:38:13 +0300
xhr-promise -- total rewrote, added retries on errors, abort method
Diffstat:
4 files changed, 91 insertions(+), 36 deletions(-)
diff --git a/src/lib/leaflet.layer.geojson-ajax/geojson-ajax.js b/src/lib/leaflet.layer.geojson-ajax/geojson-ajax.js
@@ -1,5 +1,5 @@
import L from 'leaflet';
-import {XMLHttpRequestPromise} from 'lib/xhr-promise/xhr-promise';
+import {fetch} from 'lib/xhr-promise/xhr-promise';
import {notifyXhrError} from 'lib/notifications/notifications';
L.Layer.GeoJSONAjax = L.GeoJSON.extend({
@@ -17,10 +17,11 @@ L.Layer.GeoJSONAjax = L.GeoJSON.extend({
return;
}
this._loadStarted = true;
- const {promise} = XMLHttpRequestPromise(this.url,
- {responseType: 'json', timeout: this.options.requestTimeout});
- promise.then((xhr) => this.addData(xhr.response),
- (xhr) => notifyXhrError(xhr, `GeoJSON data from ${this.url}`))
+ fetch(this.url, {responseType: 'json', timeout: this.options.requestTimeout})
+ .then(
+ (xhr) => this.addData(xhr.response),
+ (xhr) => notifyXhrError(xhr, `GeoJSON data from ${this.url}`)
+ )
},
onAdd: function(map) {
diff --git a/src/lib/leaflet.layer.westraPasses/westraPasses.js b/src/lib/leaflet.layer.westraPasses/westraPasses.js
@@ -15,14 +15,12 @@ L.Layer.WestraPasses = L.Layer.extend({
this.markers = new westraPasesMarkers(baseUrl);
this.regions1 = new L.Layer.GeoJSONAjax(baseUrl + this.options.fileRegions1, {
className: 'westra-region-polygon',
- onEachFeature: this._setRegionLabel.bind(this, 'regions1'),
- requestTimeout: 10000
+ onEachFeature: this._setRegionLabel.bind(this, 'regions1')
}
);
this.regions2 = new L.Layer.GeoJSONAjax(baseUrl + this.options.fileRegions2, {
className: 'westra-region-polygon',
- onEachFeature: this._setRegionLabel.bind(this, 'regions2'),
- requestTimeout: 10000
+ onEachFeature: this._setRegionLabel.bind(this, 'regions2')
}
);
},
diff --git a/src/lib/leaflet.layer.westraPasses/westraPassesMarkers.js b/src/lib/leaflet.layer.westraPasses/westraPassesMarkers.js
@@ -4,7 +4,7 @@ import openPopup from 'lib/popupWindow/popupWindow';
import escapeHtml from 'escape-html';
import {saveAs} from 'browser-filesaver';
import iconFromBackgroundImage from 'lib/iconFromBackgroundImage/iconFromBackgroundImage';
-import {XMLHttpRequestPromise} from 'lib/xhr-promise/xhr-promise';
+import {fetch} from 'lib/xhr-promise/xhr-promise';
import {notifyXhrError} from 'lib/notifications/notifications';
@@ -25,12 +25,11 @@ const westraPasesMarkers = L.Layer.CanvasMarkers.extend({
return;
}
this._downloadStarted = true;
- const {promise} = XMLHttpRequestPromise(this.url,
- {responseType: 'json', timeout: 30000}
- );
- promise.then((xhr) => this._loadMarkers(xhr),
- (xhr) => notifyXhrError(xhr, 'westra passes data')
- );
+ fetch(this.url, {responseType: 'json'})
+ .then(
+ (xhr) => this._loadMarkers(xhr),
+ (xhr) => notifyXhrError(xhr, 'westra passes data')
+ );
},
diff --git a/src/lib/xhr-promise/xhr-promise.js b/src/lib/xhr-promise/xhr-promise.js
@@ -1,28 +1,86 @@
-function makeRequest(url, {method='GET', data=null, responseType='', timeout=0} = {}) {
- const xhr = new XMLHttpRequest();
- xhr.open(method, url);
- xhr.timeout = timeout;
- if (responseType === 'binarystring') {
- xhr.responseType = 'text';
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- } else {
- xhr.responseType = responseType;
+function successIfStatus200(xhr) {
+ return xhr.status >= 200 && xhr.status <= 299;
+}
+
+function retryIfNetworkErrorOrServerError(xhr) {
+ return (xhr.status === 0 || xhr.status >= 500);
+}
+
+class XMLHttpRequestPromise {
+ constructor(
+ url, {method='GET', data=null, responseType='', timeout=30000, maxTries=3, retryTimeWait=1000,
+ isResponseSuccess=successIfStatus200, responseNeedsRetry=retryIfNetworkErrorOrServerError} = {}) {
+ // console.log('promise constructor', url);
+ const promise = new Promise((resolve, reject) => {
+ this._resolve = resolve;
+ this._reject = reject;
+ }
+ );
+ this.then = promise.then.bind(promise);
+ this.catch = promise.catch.bind(promise);
+ this.method = method;
+ this.url = url;
+ this._isResponseSuccess = isResponseSuccess;
+ this._responseNeedsRetry = responseNeedsRetry;
+ this._retryTimeWait = retryTimeWait;
+ this.triesLeft = maxTries;
+
+ const xhr = this.xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = () => this._onreadystatechange();
+ this._open();
+ xhr.timeout = timeout;
+ if (responseType === 'binarystring') {
+ xhr.responseType = 'text';
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ } else {
+ xhr.responseType = responseType;
+ }
}
- const promise = new Promise(function(resolve, reject) {
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4) {
- resolve(xhr);
+ _open() {
+ // console.log('open', this.url);
+ this.xhr.open(this.method, this.url);
+ }
+
+ _onreadystatechange() {
+ const xhr = this.xhr;
+ if (xhr.readyState === 4 && !this._aborted) {
+ // console.log('ready state 4', this.url);
+ if (this._isResponseSuccess(xhr)) {
+ // console.log('success', this.url);
+ this._resolve(xhr);
+ } else {
+ if (this.triesLeft > 0 && this._responseNeedsRetry(xhr)) {
+ // console.log('retry', this.url);
+ this._open();
+ this._timerId = setTimeout(() => this.send(), this._retryTimeWait);
+ } else {
+ // console.log('failed', this.url);
+ this._reject(xhr);
+ }
}
}
- });
- return {xhr, promise, send: xhr.send.bind(xhr)};
+ }
+
+ abort() {
+ // console.log('abort', this.url);
+ this._aborted = true;
+ clearTimeout(this._timerId);
+ this.xhr.abort();
+ }
+
+ send() {
+ // console.log('send', this.url);
+ this.triesLeft -= 1;
+ this.xhr.send();
+ }
}
-function XMLHttpRequestPromise(url, {method='GET', data=null, responseType='', timeout=0} = {}) {
- const {xhr, promise} = makeRequest(url, {method, data, responseType, timeout});
- xhr.send();
+function fetch(url, options) {
+ // console.log('fetch', url);
+ const promise = new XMLHttpRequestPromise(url, options);
+ promise.send();
return promise;
}
+export {fetch};
-export {XMLHttpRequestPromise, makeRequest as prepareXMLHttpRequestPromise};
-\ No newline at end of file