Skip to content

Instantly share code, notes, and snippets.

@RubaXa
Last active July 26, 2018 05:30
Show Gist options
  • Save RubaXa/be28f1bcb7f8fc1d5cb4 to your computer and use it in GitHub Desktop.
Save RubaXa/be28f1bcb7f8fc1d5cb4 to your computer and use it in GitHub Desktop.
Микро обертка для выполенения XHR-запросов
/**
* Микро обертка для выполенения XHR-запросов
* @namepace window.xhr
* @example
* xhr.load('/path/to', {type: 'POST'}, function (err, xhr) {
* // ...
* });
*/
(function (global) {
'use strict';
var _preload = {};
function noop() {
}
function newXHR(req) {
try {
req = new global.XMLHttpRequest();
} catch (err) {
try {
req = new global.ActiveXObject('Msxml2.XMLHTTP');
} catch (err) {
try {
req = new global.ActiveXObject('Microsoft.XMLHTTP');
} catch (err) {
req = {readyState: 4, status: -1};
req.open = req.send = noop;
}
}
}
return req;
}
var xhr = {
version: '0.5.0',
/**
* Вид запросов по умолчанию
* @type {boolean}
*/
async: true,
/**
* Центральная обработка запросов
* @type {Function}
*/
oncomplete: null,
/**
* Загрузить ресурс
* @param {string} url
* @param {Object|Function} [options]
* @param {Function} [callback]
*/
load: function (url, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var req = newXHR(),
async,
startTime = new Date(),
complete = function (err) {
if (err || req.readyState === 4) {
complete = noop; // затираем пустышкой
err = err || (req.status !== 200 && req.status !== 201);
req.duration = new Date() - startTime;
req.onreadystatechange = null;
callback && callback(err, req);
xhr.oncomplete && xhr.oncomplete(err, req);
}
};
options = options || {};
async = options.async === void 0 ? this.async : options.async;
req.url = url;
req.onerror = function (evt) {
req.onerror = null;
complete(evt);
};
try {
req.open(options.type || 'GET', url, async);
req.send(null);
if (async) {
req.onreadystatechange = function () {
complete();
};
}
else {
complete();
}
} catch (err) {
complete(err);
}
},
/**
* Загрузка ресурса с возможность повтора и eval для js
* @param {string} url
* @param {function} [oncomplete]
* @param {number} [attempt]
* @return {XMLHttpRequest}
*/
fetchResource: function (url, oncomplete, attempt) {
var fetchResource = xhr.fetchResource;
var filename = url.split('/').pop().replace(/(\.\w+)(\?.*)?$/, '$1');
attempt = attempt | 0;
return xhr.load(url, function (err, xhr) {
var evalTime = new Date();
xhr.error = err;
xhr.attempt = attempt;
xhr.filename = filename;
xhr.filesize = (xhr.responseText || '').length;
xhr.evalDuration = 0;
try {
// Eval source
if (!err && /\.js$/.test(filename)) {
eval.call(window, xhr.responseText + '\n//@ sourceURL=' + url);
}
} catch (error) {
err = error;
xhr.evalError = error;
} finally {
xhr.evalDuration = new Date() - evalTime;
}
if (err) {
fetchResource.onerror && fetchResource.onerror(err, xhr);
}
if (err && (attempt < fetchResource.maxAttempts)) {
// Retry
attempt++;
fetchResource.onretry && fetchResource.onretry(err, xhr);
fetchResource(url, oncomplete, attempt);
}
else {
oncomplete && oncomplete(err, xhr);
fetchResource.oncomplete && fetchResource.oncomplete(err, xhr);
}
});
},
patchRequireJS: function (require) {
require.load = function (context, moduleName, url) {
xhr.fetchResource(url, function () {
// todo: catch error;
context.completeLoad(moduleName);
});
};
},
preload: function (name, url, options) {
if (_preload[name] === void 0) {
_preload[name] = {fns: []};
}
xhr.load(url, options, function (err, xhr) {
var item = _preload[name];
item.err = err;
item.xhr = xhr;
item.fns && item.fns.forEach(function (fn) {
fn(err, xhr);
});
item.fns = null;
});
},
wait: function (name, oncomplete) {
var item = _preload[name];
if (item === void 0) {
_preload[name] = {fns: [oncomplete]};
} else if (item.xhr === void 0) {
_preload[name].fns.push(oncomplete);
} else {
oncomplete(item.err, item.xhr);
}
}
};
/**
* Последовательная загрузка ресурсов
* @param {string[]} urls
* @param {function} [oncomplete]
*/
xhr.fetchResource.series = function fetchResourceSeries(urls, oncomplete) {
var queue = urls.slice(0); // clone
(function _fetchNext() {
var url = queue.shift();
if (url) {
xhr.fetchResource(url, function (err) {
if (err) {
oncomplete(err);
} else {
_fetchNext();
}
});
} else {
oncomplete();
}
})();
};
/**
* Масимальное кол-во попыток при загрузке ресурсов
* @type {number}
*/
xhr.fetchResource.maxAttempts = 2;
// Export
global['xhr'] = xhr;
})(window);
(function(l){function m(){}function p(a){try{a=new l.XMLHttpRequest}catch(c){try{a=new l.ActiveXObject("Msxml2.XMLHTTP")}catch(d){try{a=new l.ActiveXObject("Microsoft.XMLHTTP")}catch(b){a={readyState:4,status:-1},a.open=a.send=m}}}return a}var h={},g={version:"0.5.0",async:!0,oncomplete:null,load:function(a,c,d){"function"===typeof c&&(d=c,c={});var b=p(),k=new Date,e=function(a){if(a||4===b.readyState)e=m,a=a||200!==b.status&&201!==b.status,b.duration=new Date-k,b.onreadystatechange=null,d&&d(a,
b),g.oncomplete&&g.oncomplete(a,b)};c=c||{};var f=void 0===c.async?this.async:c.async;b.url=a;b.onerror=function(a){b.onerror=null;e(a)};try{b.open(c.type||"GET",a,f),b.send(null),f?b.onreadystatechange=function(){e()}:e()}catch(q){e(q)}},fetchResource:function(a,c,d){var b=g.fetchResource,k=a.split("/").pop().replace(/(\.\w+)(\?.*)?$/,"$1");d|=0;return g.load(a,function(e,f){var g=new Date;f.error=e;f.attempt=d;f.filename=k;f.filesize=(f.responseText||"").length;f.evalDuration=0;try{!e&&/\.js$/.test(k)&&
eval.call(window,f.responseText+"\n//@ sourceURL="+a)}catch(n){e=n,f.evalError=n}finally{f.evalDuration=new Date-g}e&&b.onerror&&b.onerror(e,f);e&&d<b.maxAttempts?(d++,b.onretry&&b.onretry(e,f),b(a,c,d)):(c&&c(e,f),b.oncomplete&&b.oncomplete(e,f))})},patchRequireJS:function(a){a.load=function(a,d,b){g.fetchResource(b,function(){a.completeLoad(d)})}},preload:function(a,c,d){void 0===h[a]&&(h[a]={fns:[]});g.load(c,d,function(b,c){var e=h[a];e.err=b;e.xhr=c;e.fns&&e.fns.forEach(function(a){a(b,c)});
e.fns=null})},wait:function(a,c){var d=h[a];void 0===d?h[a]={fns:[c]}:void 0===d.xhr?h[a].fns.push(c):c(d.err,d.xhr)}};g.fetchResource.series=function(a,c){var d=a.slice(0);(function k(){var a=d.shift();a?g.fetchResource(a,function(a){a?c(a):k()}):c()})()};g.fetchResource.maxAttempts=2;l.xhr=g})(window);
@dmitryshimkin
Copy link

xhr.open может бросить исключение. Нужен try/catch для req.open(options.type || 'GET', url, async);

@RubaXa
Copy link
Author

RubaXa commented Oct 14, 2015

Да, точно, поправил.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment