Skip to content

Instantly share code, notes, and snippets.

@ishiduca
Created September 5, 2011 04:46
Show Gist options
  • Save ishiduca/1194111 to your computer and use it in GitHub Desktop.
Save ishiduca/1194111 to your computer and use it in GitHub Desktop.
「リクエストを受けた順番に通信&処理を行うXMLHTTPクライアント」のプロトタイプ
this.QUERY = new Query;
// var client = {};
//
// /* client.A と client.B は非同期 */
// client.A = client.A || new XMLHttpClient;
// client.B = client.B || new XMLHttpClient;
//
// /*
// pushしたリクエストは、pushした順番に処理。
// 1つのリクエストを処理を完了するまで、次のリクエストは待っている
// */
//
// client.A
// .push('GET', '/path?foo=hoge', function (response) { ... })
// .push('GET', '/path?user=unknown&pass=0123', function (response) { ... })
// ;
//
// client.B
// .push('GET', '/path_another?foo=hoge', function (response) { ... })
// .push('GET', '/path_another?user=yourself&pass=both', function (response) { ... })
// ;
//
// /* listenメソッドで通信(&処理)を開始する */
// client.A.listen();
// client.B.listen();
function XMLHttpClient () {
this.queue = [];
this.state = false;
this.client = new XMLHttpRequest();
}
(function () {
function _reFormatHttpRequest1 (method) {
if (method === 'POST') {
if (this[0].match(/\?/)) {
var buf = this[0].split(/\?/);
this[0] = buf[0];
this[1] = buf[1];
}
}
}
function _reFormatHttpRequest2 (method) {
// this[1] == null 以外は、stringに直し、method === 'POST' -> body, method === 'GET' -> urlに追加
var buf = QUERY.stringify(this[1]);
if (method === 'POST') {
this[1] = buf;
} else {
this[1] = null;
this[0] = (buf) ? [ this[0], buf ].join((buf.match(/^\?/)) ? '' : '?') : this[0];
}
}
function reFormatHttpRequest (method, httpRequest) {
if (! method) return { error : '"method" not found' };
if (! httpRequest) return { error : '"httpRequest object" not found' };
method = (method.match(/^post/i)) ? 'POST' : 'GET';
var url, body = null, headers = {}, httpRequestObj = [ url, body, headers ];
if (typeof httpRequest === 'string') {
httpRequestObj[0] = httpRequest;
_reFormatHttpRequest1.apply(httpRequestObj, [ method ]);
return httpRequestObj;
}
if (! httpRequest.length) return { error : 'httpRequest must be "string" or "array"' };
if (typeof httpRequest[0] !== 'string') return { error : '"url" must be "string"' };
httpRequestObj[0] = httpRequest[0];
_reFormatHttpRequest1.apply(httpRequestObj, [ method ]);
httpRequestObj[1] = httpRequest[1] || httpRequestObj[1];
_reFormatHttpRequest2.apply(httpRequestObj, [ method ]);
httpRequestObj[2] = httpRequest[2] || {};
return httpRequestObj;
}
XMLHttpClient.prototype.push = function (method, httpRequest, callback, async) {
method = (method.match(/^post$/i)) ? 'POST' : 'GET';
httpRequest = reFormatHttpRequest(method, httpRequest);
if (method === 'POST') httpRequest[2]['Content-Type'] = 'application/x-www-form-urlencoded';
this.queue.push({
method : method,
url : httpRequest[0], // url,
body : httpRequest[1], // body,
headers : httpRequest[2], // headers,
callback : callback,
async : (async === false) ? false : true // 明示的に false しないと、true で非同期処理
});
return this;
};
XMLHttpClient.prototype.listen = function () {
if (this.queue && this.queue.length > 0) {
if (this.state) {
setTimeout(this.listen, 1);
} else {
run.apply(this); //this.run();
}
}
return this;
};
//XMLHttpClient.prototype.run = function () {
function run () {
var self = this,
client = this.client,
req
;
if (this.queue.length > 0) {
this.state = true;
req = this.queue.shift();
client.onreadystatechange = function () {
if (client.readyState === 4) {
if (client.status >= 200 && client.status < 300) {
var responseHeaders = {};
client.getAllResponseHeaders().split(/\r\n/).foreach(function (header) {
var keyVal = header.split(/:\s?/);
responseHeaders[keyVal[0]] = keyVal[1];
});
req.callback([ client.status, responseHeaders, client.responseText ]);
} else {
throw new Error([ client.status, client.statusText ].join(': '));
}
self.state = false;
if (self.queue && self.queue.length > 0) self.listen(); // あやしい
} else {
;
}
};
client.open(req.method, req.url, req.async);
if (req.headers) {
for (var key in req.headers) {
client.setRequestHeader(key, req.headers[key]);
}
}
client.send(req.body);
}
return this;
}//;
}) ();
// query
function Query () {};
(function (Q) {
Q.parse = function (str, type) {
type = type || 'HASH';
type = (type.match(/^array$/i)) ? 'ARRAY' : 'HASH';
if (! str) return (type === 'ARRAY') ? [] : {};
if (typeof str !== 'string') return { error: 'failed: 1st argument must be "string"' };
str = (str.match(/^\?/)) ? str.slice(1) : str;
var obj, buf;
if (type === 'ARRAY') {
obj = [];
(str.split(/&/)).foreach(function (keyVal) {
buf = keyVal.split(/=/);
obj.push([ buf[0], decodeURIComponent(buf[1]) ]);
});
return obj;
}
if (type === 'HASH') {
obj = {};
(str.split(/&/)).foreach(function (keyVal) {
buf = keyVal.split(/=/);
obj[ buf[0] ] = decodeURIComponent(buf[1]);
});
return obj;
}
};
Q.stringify = function (obj) {
if (! obj) return null; // '';
if (typeof obj === 'string') return obj;
var buf = [];
if (obj instanceof Array) {
obj.foreach(function (keyVal) {
buf.push([ keyVal[0], encodeURIComponent(keyVal[1]) ].join('='));
});
return (buf.length > 0) ? buf.join('&') : null;
}
if (typeof obj === 'object') {
for (var key in obj) {
buf.push([ key, encodeURIComponent(obj[key]) ].join('='));
}
return (buf.length > 0) ? buf.join('&') : null;
}
return { error: 'failed: arguments must be "hash" or "array"' };
};
}) (Query.prototype);
@ishiduca
Copy link
Author

ishiduca commented Sep 5, 2011

  • readyState < 4 の時の処理
  • status != 2xx の時の処理
  • uri, requestheader の処理

@ishiduca
Copy link
Author

function foreach (arry, func) {
var i =0, len = arry.length;
if (len) {
for (; i < len; i += 1) {
func(arry[i], i);
}
}
}
if (! Array.prototype.foreach) {
Array.prototype.foreach = function (func) {
foreach.apply(null, [ this, func ]);
};
}

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