Skip to content

Instantly share code, notes, and snippets.

@RubaXa
Last active July 26, 2018 05:30
Show Gist options
  • Select an option

  • Save RubaXa/be28f1bcb7f8fc1d5cb4 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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

@RubaXa
Copy link
Copy Markdown
Author

RubaXa commented Oct 14, 2015

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

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