试了试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墙, 也许,你会遇到心仪的项目