Created
September 5, 2011 04:46
-
-
Save ishiduca/1194111 to your computer and use it in GitHub Desktop.
「リクエストを受けた順番に通信&処理を行うXMLHTTPクライアント」のプロトタイプ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
Author
ishiduca
commented
Sep 5, 2011
- readyState < 4 の時の処理
- status != 2xx の時の処理
- uri, requestheader の処理
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