试了试Chrome下的插件开发,简单将一些有意思的东西列了出来,其中一个就是XMLHttpRequest。
关于XMLHttp维基上有下面的介绍
XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。
XMLHTTP是AJAX网页开发技术的重要组成部分。
除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。
在Chrome的开发文档中有:
普通网页能够使用XMLHttpRequest对象发送或者接受服务器数据, 但是它们受限于同源策略. 扩展可以不受该限制. 任何扩展只要它先获取了跨域请求许可,就可以进行跨域请求。
之前没有试过用原生的XMLHTTP写过代码,也算是一种不象牙的体验。
于是看到官方的文档是这样子的
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange;
xhr.open("GET", chrome.extension.getURL('/config_resources/config.json'), true);
xhr.send();
最后只需要return个
xhr.responseText
就可以了。
于是看了看jQuery的ajax首先是这样的一个函数,提供XHR
jQuery.ajaxSettings.xhr = function() {
try {
return new XMLHttpRequest();
} catch( e ) {}
};
然后有
xhrSupported = jQuery.ajaxSettings.xhr();
support.ajax = xhrSupported = !!xhrSupported;
越往后面越复杂就不继续了,看看Amazon是怎么封装的。
先看看一个简单的对Amazon的XHRClient的封装
XHRHelper.prototype.request = function(url, callback) {
var xhrClient = new XHRClient();
var options = {};
options["success"] = function(response) {
callback(response);
};
xhrClient.request(url, options);
}
用的时候就是这么用的
var xhrHelper = new XHRHelper();
xhrHelper.request(url, function(result) {
console.log(result);
});
但是封装之前的代码呢?
首先会对传进来的参数做一个merge,这也就是我们只传进一个options["success"]的原因。
options = options || {};
_.defaults(options, {
http_method: "GET",
responseType: "json",
headers: {},
success: function() {},
error: function() {},
data: {},
timeout: 0,
cacheDateHeader: false
});
不得不说这确实是一个好的方法——用来处理一些默认的选项。
接着对options进行了一些处理
if (!url || typeof url !== "string") {
options['error'](new Error("URL is an invalid type"));
}
if (options['http_method'] === HTTP_METHOD['GET']) {
url += hasParams(url) ? "&" : "?";
url += serialize(options['data']);
}
request.open(options['http_method'], url, true);
_.each(_.keys(options['headers']), function(key) {
request.setRequestHeader(key, options['headers'][key]);
});
request.responseType = options['responseType'];
request.timeout = options['timeout'];
request.ontimeout = function() {
options['error'](new Error("The request timed out"));
};
然后是获取数据,如果可以获取到数据的时候,解析数据。
request.onreadystatechange = _.bind(function() {
if (request.readyState === STATE.DONE) {
if (request.status === STATUS.OK) {
var response, error = new Error("Unable to parse the response");
try {
response = parseResponse(request);
}
catch(e) {
response = null;
}
if( response ) {
options['success'](response);
} else {
options['error'](error);
}
} else {
var error = new Error("Request completed with a non-200 status code");
error.status = request.status;
error.statusText = request.statusText;
options['error'](error);
}
} else if (request.readyState === STATE.HEADERS_RECEIVED) {
var httpResponseHeaderDate = request.getResponseHeader("Date");
if (httpResponseHeaderDate && options.cacheDateHeader) {
try {
var serverClientTimePairObject = {
"serverTime" : Date.parse(httpResponseHeaderDate),
"clientTime" : Date.now()
};
} catch (error) {}
}
}
},this);
下面的代码是来自Amazon的,除去之前的模块化——亚马逊1Button App源码分析之JavaScript模块化思想,我们关注一下这个实现:
var Ajax = function() {};
Ajax.prototype = {
get: function(url, cb) {
cb = cb || lang.noop;
if (typeof XMLHttpRequest !== "undefined") {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
cb(null, xhr.responseText);
} else {
var err = new Error("Server returned with non-200 status code: " + xhr.status);
err.xhr = xhr;
cb(err);
}
}
}
xhr.send();
}
}
};
实现上只是刚之前的xhr-client.js
重新实现了一遍,然后在上面写着
/**
* @exports a singleton instance of Ajax
*/
在zepto
(ps:jQuery兼容库)中是这样实现的:
$.ajax = function(options){
xhr.setRequestHeader = setHeader
xhr.onreadystatechange = function(){
if (xhr.readyState == 4) {
xhr.onreadystatechange = empty
clearTimeout(abortTimeout)
var result, error = false
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'))
result = xhr.responseText
try {
// http://perfectionkills.com/global-eval-what-are-the-options/
if (dataType == 'script') (1,eval)(result)
else if (dataType == 'xml') result = xhr.responseXML
else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
} catch (e) { error = e }
if (error) ajaxError(error, 'parsererror', xhr, settings, deferred)
else ajaxSuccess(result, xhr, settings, deferred)
} else {
ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred)
}
}
}
return xhr
}
围观我的Github Idea墙, 也许,你会遇到心仪的项目