此类的作用是,根据当前的浏览器环境,创建一个正确的XMLHttpRequest/ActiveXObject 对象(这个是原生的对象)。
同时定义了goog.net.XmlHttp.ReadyState ,其中分别定义了readystate 0-4的名字。
此类是一个基础类,作用是为其他类提供一个可以跨浏览器的XHR对象,因此不建议直接使用此类
一般使用此类来进行ajax通信。
此类继承自EventTarget,其内部使用XmlHttp来实现。基本原理是:创建XmlHttp来实现基本的通信功能,对XmlHttp的不同状态,触发相应的事件goog.net.EventType,并对浏览器的差异进行处理。
此类还提供了一个静态的send方法,因此如果只是很简单的通信,可以直接使用goog.net.XhrIo.send(xxxxx);但是一般通过new good.net.XhrIo 来创建对象,然后用注册监听的方法实现其他功能。
源码解析:
goog.net.XhrIo(opt_xmlhttpFactory):构造方法,可以传入一个工厂函数来产生XHR对象,否则使用默认的工厂函数。
并继承自EventTarget,因此是一个标准的事件源,可以用listen来注册监听。
goog.net.XhrIo.sendInstances_:用静态send方法所产生的对象都存在这里,以方便统一销毁。
goog.net.send():静态方法,其原理是创建一个临时的XhrIo对象来进行通信,然后再销毁这个对象。注意在这里是将回调函数注册到了complete事件上而不是success事件上,所以请求错误也会调用回调函数。
timeout参数是全局的,而不是这个临时对象专有的。
goog.net.prototype.send():创建一个XHR进行通信,并将注册onreadystatechange = this.onreadystatechange_,
goog.net.prototype.onreadystatechange_():调用了onReadyStateChangeHelper_ 。
goog.net.prototype.onReadyStateChangeHelper_():在此函数中,根据相应的状态,触发了对应的goog.net.EventType事件。
goog.net.prototype.getResponseText():获得返回结果的文本
goog.net.prototype.getResponseJson():调用goog.json.parse来将返回文本解析成json数据并返回。
注意:使用send静态方法时要注意xhr对象的生命周期。
当使用静态send方法时,在回调函数执行完后会销毁xhr实例,所以如下使用是错误的:
goog.net.XhrIo.send('http://www.example.com/testdata.txt', function(e) {
var xhr = /** @type {goog.net.XhrIo} */ (e.target);
// Instead of doing the alert right away, call it in a timeout. setTimeout(function() { alert(xhr.getResponseText()); }, 1000);
});
因为setTimeout是在新的线程中异步执行的,但是此时xhr对象已经被销毁,所以会导致错误。如下方法才是正确的:
goog.net.XhrIo.send('http://www.example.com/testdata.txt', function(e) {
var xhr = /** @type {goog.net.XhrIo} */ (e.target);
var responseText = xhr.getResponseText();
setTimeout(function() { alert(responseText); }, 1000);
});
在xhr被销毁之前,把需要用的responseText取出来存在另外一个变量中,就可以避免在异步访问中发生错误。
注意两个常用的类型的区别:COMPLETE和SUCCESS
无论是否发送成功,总是会触发COMPLETE事件,包括 由于 超时,服务器端错误,网络故障等造成的错误。
但是SUCCESS只有在请求成功时才会触发,触发顺序如下:
->complete->success/error/abort
使用prioritypool来管理所有的xhr请求,当xhr资源可用时,会自动挑选最高优先权的xhr来执行。当一个页面需要大量的发送xhr请求时,可以使用xhrmanager来做。
优点:
自动管理优先级
自动管理大量的并发请求
可以自动重发失败的请求
两个重要方法:
goog.net.XhrManager(opt_maxRetries, opt_headers, opt_minCount, opt_maxCount, opt_timeoutInterval):构造函数,maxRetries:请求失败后,最多重发次数。
headers:指定头部, minCount:pool中最少存在的xhr数量,maxCount:最大数量。timeoutInterval:超时时间。
因为是在xhrmanager的构造函数中传入的参数,所以这些设置是此manager中所有xhr公用的。
goog.net.XhrManager.prototype.send(
id: 此请求的id,这个id是必须的,之后想操作这个请求,比如:取消它,就需要用到这个id。
url:请求的url。
opt_method:回调函数
opt_content:
opt_headers:
opt_priority:
opt_callback:
opt_maxRetries:
}
创建XhrManager对象之后可以直接使用此方法来发送请求。
封装了对uri的常用操作,类似于location对象中的方法,但是比它强大。用法如下
var googUri = new goog.Uri(uri);
googUri.getScheme(); googUri.getUserInfo(); googUri.getDomain(); googUri.getPort(); googUri.getPath(); googUri.getQuery(); googUri.getFragment();
同get方法还有对应的set方法。
如果不想new一个对象,可以使用对应的goog.uri.utils.xxx静态方法,可以直接对uri字符串进行操作
如 goog.uri.util.getScheme("http://www.baidu.com") == (new goog.Uri("http://www.baidu.com")).getScheme();
getQuery(在utils中是getQueryData)方法:会返回一个QueryData对象。类似于一个map,不过不同的是这个map是一对一或者一对多的关系。
因为同一个参数可能被多次赋值,这是允许的。比如:?a=1&a=2&a=3
假设想从多个url请求数据,并处理这些数据的集合,则可以使用BulkLoader。
bulkloader可以从一个urls数组获取数据,并把结果按照url的顺序存在一个数组并返回。
它的好处是 可以保证返回结果的顺序和请求地址中的顺序对应,并封装了对错误的处理。
var bulkLoader = new goog.net.BulkLoader(urls); goog.events.listen(bulkLoader,
[goog.net.EventType.SUCCESS, goog.net.EventType.ERROR], function(e) {
if (e.type == goog.net.EventType.SUCCESS) {
// We use unsafeParse here because we trust the source of the data. var loader = /** @type {goog.net.BulkLoader} */ (e.target);
var json = goog.array.map(loader.getResponseTexts(),
goog.json.unsafeParse), showEventsOnCalendar(json);
} else {
// Here, e.type is goog.net.EventType.ERROR
alert('Oh no - I should add some error handling here!'); }
bulkLoader.dispose(); });
bulkLoader.load();
源码解析:
goog.net.BulkLoader(urls):构造函数,传入一个参数是url的数组。此类是EventTarget的子类。内部保存了一个BulkLoaderHelper的实例helper_。
bulkload主要做的是:新建一个BulkLoaderHelper实例,将urls传给他。然后从urls中诸葛取出url,创建xhr,把返回结果和序号交给bulkloaderhelper保存。
load():取得数据。遍历urls数组,对每一个url,新建一个xhr链接取数据,回调函数handleEvent_,注意这里将对应的index传给了handleEvent_。
handleEvent_(id,e):如果成功,则handleSuccess_(id, xhrIo);失败则handleError_(id, xhrIo);
handleSuccess_(id, xhrIo):调用helper_.setResponseText(id, xhrIo.getResponseText),传入的是当前url的index和返回结果。然后调用helper_.isLoadComplete()来判断是否加载完毕,如果是,则调用finishLoad_()来触发SUCCESS事件。
handleError_(id, xhrIo):触发ERROR事件。handleSuccess_和handleError_最后都会调用xhrIo.dispose()来销毁对象。
goog.net.BulkLoaderHelper(uris):保存uris_,建立一个responseTexts_空数组用来存储返回结果。其作用就是管理uris和responseText_两个数组。
getUri(id):return this.uris_[id];
getUris():return this.uris;
setResponseText(id, responseText):把responseText存在this.responseTexts[id]中。
getResponseTexts():return this.responseTexts_;
isLoadComplete():遍历this.responseTexts_数组,如果其length和uris.length一样,并且其中每一项都已经被赋值,则返回true,否则返回false。
可以并行地加载多个图片资源。比如程序需要加载多张图片之后执行某些操作,或者想在加载网页其他部分的时候预加载图片,可以使用此类来实现。
原理:创建Image实例(new Image();或者 createElement("img"),其实就是一个DOM元素<img>),然后赋值img.src="xxx",此时浏览器会自动发送请求加载图片。加载完成后,可以读取图片的信息(比如img.width),如果传入的构造参数是一个img元素,则此图片会直接显示。
var loader = new good.net.ImageLoader();
loader.addImage("img-1","http://www.baidu.com/img/baidu_sylogo1.gif");//添加一个img。
loader.start();//开始加载所有图片。
当iframe加载完成后触发一个事件(无论是加载成功还是失败)。
以http://example.com/mypage.html为例,以下情况都算作跨域通信:
URL Why access is denied
http://google.com/ Different domain
https://example.com/mypage.html Different protocol
http://example.com:8080/index.jsp Different port
http://www.example.com/mypage.htmlDifferent subdomain
ajax是不能进行跨域通信的,closure提供了两个跨域通信的工具:goog.net.Jsonp 和 goog.net.xpc
jsonp用来进行跨域通信。其原理是:创建一个script标签,指定src属性值,此时浏览器会自动发送请求获取内容并执行其中的js代码。
示例:
var jsonp = new goog.net.Jsonp('http://example.com/birthdays', 'callback'); // By default, the JSONP request is cancelled if it does not return within // 5 seconds, so this increases the timeout to 10 seconds. jsonp.setRequestTimeout(10 * 1000); var errorCallback = function() { alert('The request failed to return within 10 seconds'); }; // The send() method is responsible for creating and destroying the <script> // tag that points to example.com. jsonp.send(null /* payload */, showBirthdays, errorCallback);
源码解析:
goog.net.Jsonp(uri, opt_callbackParamName):构造函数,第一个参数是uri,第二个参数是uri后面的callback参数名(注意,不是请求成功后的回调函数,也不是callback参数值,而是 www.xx.com?callback=abc中的callback名),如果不设定,则默认是callback。
goog.net.Jsonp.send(
opt_payload, 以get方式添加的参数,name-value类型的
opt_replyCallback, 请求成功后的回调函数,会传一个参数就是请求的返回结果
opt_errorCallback, 请求失败后的回调函数,会把opt_payload当参数穿进去
opt_callbackParamValue opt) callbackParamName参数的值
);
发送请求。
创建一个script标签。然后设置timeout以在超时后调用error函数执行超时操作。创建一个uri,并追加相应的参数(payload等)。
把对应的callback存储在goog.global[goog.net.Jsonp.CALLBACKS][id]中,这个id是自动生成的唯一标示。
将script标签赋值src,并append到head中(此时浏览器会自动发请求加载内容,并执行其中的js代码)
另一个跨域通信的类,主要用来在不同域的iframe之间进行通信。
先有必要了解下window.postMessage:
新特性,可以用来在不同域的iframe之间进行通信。
例如:在iframe0中:
frame = window.iframe[1]; frame.postMessage(xxx); //获取一个iframe1引用,并用它来发送一个信息。
在iframe1中:
window.addEventListener("message", callback); //iframe中可以捕获上面发送的那个消息。