1、引子
引出本次讨论的原因是dojo.io.IframeIO的问题。在一个比较大的Javascript应用中使用了dojo,dojo.io是dojo实现的非常好的一个地方,因为dojo.io用一个通用的接口封装了XmlHttp、Iframe、ScriptSrc这几种主流方式(Facade模式),是处理Ajax应用IO的很好选择。但是项目实际部署以后发现经常出现操作无响应的情况,经过反复排查发现是使用的dojo.io.IframeIO的排队没有超时造成的。
那么我们就要寻找问题再哪里呢?
2、问题
首先我们看到了dojo.io的bind方法中支持通用的timeout和timeoutSeconds参数,这两个参数从语意上看是为了给你的IO增加超时机制。当初Ajaxian上有一篇介绍实际部署的Ajax项目需要注意的稳定性问题,其中比较重要的一条就是要给你的通讯排队增加超时,而dojo.io的这种设计正体现了这种观点。那么我们还是首先分析一下为什么要排队和为什么要超时机制。
io通讯分同步和异步两种方式,同步即需要阻塞等待,异步即无阻塞等待(异步回调)。我们在使用XML Http的时候可以选择asynchronous为true和false,大家都知道它们就是是否同步。使用的地方大家都很熟悉了,比如两个function有关,它们的调用需要保证严格顺序,那么就应该同步通讯,前一个完了再调后一个。反之如果几个function之间无关,那么就可以异步通讯,减少用户浏览器的阻塞和等待。
OK,这种模型很清楚和简单。可是,实际上就XMLHttp而言,我们一般尽量不使用asynchronous=false,因为这样浏览器会在传输的时候失去对用户的响应,用户感觉比较差。对于需要严格顺序的通讯我们使用另外一种方式,那就是回调的时候再调用下面一个函数,这样也可以保持严格顺序,形成调用链。这种方式其实就是排队模型 。在dojo中有一个queueBind方法,实际上就是包装过的调用链。有了这些机制就可以满足我们日常的编程模型了,似乎很完美了。
可是,问题在于并非所有io都可以提供排队和非排队的方式进行通讯。比如iframe和ScriptSrc的方式实际上都是不支持非排队的,因为这些通讯本质上都是同步的(或者说假异步),在只有一个Dom元素(iframe或者script元素)进行通讯的时候其实所有的io都必须排队。也就是说可怜的iframe和scirptSrc方式都只有排队……而不能不排队……。这似乎也没什么问题,但是问题来了……
HTTP通讯并非可靠的通讯,它们都是最大努力的传输方式,也就是说丢包是不可避免的,在发生丢包的时候如果恰巧你的通讯进行了排队而此时又没有超时……那么你惨了,就出现了北京早晚场出现的堵车现象,往往仅仅是一辆辆车刮蹭了,后面的车就永久的成为了化石,多么的悲壮呀。
所以,排队的超时就非常重要了!一次通讯一定要有超时时间,这样在阻塞时可以把阻塞消除。
dojo在BrowserIO(XMLHttp)和ScriptSrcIO里面实现了超时机制,但是在IframeIO中没有提供,这可能是个历史遗留。
而引子中所说的问题正来自这个不公平的待遇,iFrame的bind实际上就是queueBind(因为dojo的iFrameIO只用了一个iFrame),而又没有超时机制……,然后应用部署在实际网络条件后就有很多用户遇到了操作无响应的问题。
3、解决
找到问题并理清思路离解决就非常近了。
dojo的BrowserIO(XMLHttp)和ScriptSrcIO都使用了一种类似onFlight的方式检查超时。就是纪录通讯开始时间,然后传输时开始轮训检查是否超时。不直接用setTimeout检查通讯超时是因为如果有多个ScriptSrc或者XMLHttp通讯的时候可以防止互相冲突。
我们也可以比较简单的向IframeIO中添加添加这样的功能:
OK,这里我偷懒了……。因为我们的项目只有一个iFrame作io,所以我们没有使用onFlight方式,使用了setTimeout直接检查的方式。大家先笑纳,待简单修正把IframeIO也修改为onFlight的方式(然后提交dojo?)。
如此看有点虎头蛇尾,实际上就是这样,问题很大解决方法很小。我们经常遇到的就是这样的问题。
4、尾声
最后其实还是要回到javascript应用中的io问题上来。这里我还要简单写一下我们常用到的io方式,我身边还有很多同事不了解所以然。
XML Http是这几个io中最好的一个,因为它是一个完整的IO实现,有状态回调机制,有abort等处理方法,但是相对来说有几个限制:浏览器支持、文件上传、跨域。
浏览器支持现在倒不算个问题,Ajax应用普遍是IE 5.5+、FF 1.0+、Opera 8+这样子,它们都支持XMLHttp了。文件上传用XMLHttp也比较难解决,虽然可以用客户端切分的方法,但是用的人实际上很少(在这点上技术复杂性超过了iframe很多)。
XMLHttp最大的限制是跨域,很严格,甚至不能跨子域,这给我们的通讯带来了巨大的限制。因为很多时候我们要使用proxy或者负载均衡的分布式来解决这个问题,这就增加了部署复杂性。
相对来说iframe则放松了这样的限制,你可以跨子域(比如www.abc.com和ajax.abc.com和cde.xxx.abc.com),我们可以在文档里面通过domain="abc.com"来强制用根域做js执行的域。但是这种做法也有麻烦,比如Firefox 1.0.x的一些版本如果domain="abc.com"执行以后会造成XMLHttp通讯失败,此时我们就没法在用iframe的同时用XMLHttp了。
iframe的另外一种好处是它比较容易解决文件上传的问题,只要对form指向一下target为iframe就可以无刷新上传了,这几乎是最简单的方案。
但是iframe的限制还是满多的,它比较复杂,在Tencent这样的倒霉浏览器中设置了所有链接都在新窗口中打开后会让应用很难看并不可用,它没有完全的解决跨域问题等等。
为了解决iframe的不能跨根域的问题,引入了ScriptSrc的方式。就是指<script src="xxx.js" id="scriptIo"></script>,然后动态修改src这样的方式。为了浏览器兼容,此种方式下需要动态的创建script节点,然后再删除,否则内容不会载入(非IE的情况)。所以技术复杂度相对也比较高。但是这种方式可以完全解决跨域问题,你可以将src指向任何地方!
那么缺点是ScriptSrc在动态删节点的时候潜在存在内存泄露,据称不太好解决。而更大的问题是如果传输json的话,必须用var json = {property:value};这样的形势,对json有了污染,不太好。
所以,对于io的方案主要来说几个点:
a、跨域:ScriptSrc完全跨域,iFrame跨子域,XmlHttp不跨域。
b、文件:传文件iframe比较简单,ScriptSrc和XmlHttp都需要客户端切分get上去,比较麻烦。
c、生命周期控制:XmlHttp比较完善,而iFrame可以模拟但是不完全,ScriptSrc则更难。
That's all。本来想No fluff just staff的写这篇东西,但是无奈嘴碎写的优点乱,请大家见谅。关于本问题的解决希望大家多提意见,互相交流。
- IframeIO.0.4.3.rar (5.1 KB)
- 描述: 对dojo.io.IframeIO的修改及原文件,可以进行参照。这个补丁只是拍脑袋就来的临时实现,与dojo的其它超时的实现不一致,需要改进。
- 下载次数: 83
分享到:
- 2007-05-23 11:32
- 浏览 7722
- 评论(7)
- 论坛回复 / 浏览 (3 / 9974)
- 查看更多
相关推荐
dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2dojo.js 1.4.2
dojo.js.uncompressed.js 1.4.2dojo.js.uncompressed.js 1.4.2dojo.js.uncompressed.js 1.4.2
在Dojo 0.3.1中,`dojo.io.bind`是一个更底层的AJAX接口,它可以处理更多的细节,如自定义请求头、超时和自定义HTTP方法。不过,它不如xhr系列方法常用,因为后者的API更简洁。 9. **dojo.Deferred对象** Dojo中...
2. **AJAX实现**:dojo库中的`dojo.xhr`模块是实现AJAX的核心部分。它提供了一系列的函数,如`dojo.xhrGet`、`dojo.xhrPost`等,用于向服务器发送异步请求,获取或发送数据,从而实现页面无刷新的数据交互。 3. **...
dojo学习笔记(一)-dojo.io.IO & dojo.io.BrowserIO) dojo学习笔记(三) dojo学习笔记(二) dojo.lang.array & dojo.lang.func & dojo.string.extras dojo学习笔记(六)- ContentPane dojo学习笔记(四)...
8. **dojo.on**: 用于事件监听,`dojo/on`模块提供了更高级别的事件处理,可以方便地为DOM元素或其他对象添加事件监听器。 9. **dojo/json**: 提供了JSON序列化和反序列化的功能,如`dojo/json::parse`和`dojo/json...
**DOJO.js 框架详解** DOJO.js 是一个功能强大的JavaScript库,它被誉为“最优秀的js框架”之一,特别是在版本1.9.3中,这个称号得到了充分的体现。DOJO以其全面的特性、模块化的设计以及对各种浏览器的良好支持而...
dojo学习笔记(一)-dojo.io.IO & dojo.io.BrowserIO) dojo学习笔记(三) dojo学习笔记(二) dojo.lang.array & dojo.lang.func & dojo.string.extras dojo学习笔记(六)- ContentPane dojo学习笔记(四)...
dojo学习笔记(一)-dojo.io.IO & dojo.io.BrowserIO) dojo学习笔记(三) dojo学习笔记(二) dojo.lang.array & dojo.lang.func & dojo.string.extras dojo学习笔记(六)- ContentPane dojo学习笔记(四)...
- AJAX通信:Dojo的IO模块支持异步数据请求,如`dojo.io.*`,便于与服务器进行数据交互。 - UI组件:`dojo.widget.*`包含了多种可复用的UI组件,如按钮、表单元素等,方便快速构建用户界面。 - 动画效果:Dojo的动画...
dojo.xd.js 最新JavaScript框架组件!
dojo.js
1. **Dojo基础**:首先,读者会了解到Dojo的核心概念,如dojo.js加载器、dojo.declare用于类定义、dojo.connect用于事件处理,以及dojo.query用于DOM查询。这些基础知识是理解Dojo工作的关键。 2. **模块系统(AMD...
【Dojo.GUI_v6.zip for pencil】是一款专为Pencil设计的GUI模板资源包,它扩展了Pencil这款优秀的Web原型设计工具的功能和视觉元素。Pencil是一个免费且开源的应用程序,允许用户创建各种交互式原型,适用于网页、...
dojo.js.uncompressed.js 1.92版
dojo学习笔记(一)-dojo.io.IO & dojo.io.BrowserIO) dojo学习笔记(三) dojo学习笔记(二) dojo.lang.array & dojo.lang.func & dojo.string.extras dojo学习笔记(六)- ContentPane dojo学习笔记(四)...
`dojo.io.IO` 和 `dojo.io.BrowserIO` 是处理 I/O 任务的关键模块,包括发送 AJAX 请求和处理服务器响应。`dojo.dom` 模块则提供了操作 DOM(文档对象模型)节点的方法,如查找、创建、修改和删除元素。 `dojo....
7. **dojo.io.script**: 对于需要从外部脚本服务获取数据的情况,如Google Maps API,Dojo提供了`dojo.io.script`模块。它允许开发者通过`<script>`标签进行异步请求,通常用于实现JSONP或跨域脚本服务。 8. **dojo...
根据给定文件的信息,我们可以提炼出以下关于《使用Dojo JavaScript库构建Ajax应用程序》的关键知识点: ### 一、Dojo JavaScript库简介 Dojo是一个开源的JavaScript库,它提供了丰富的功能来帮助开发者创建高性能...
domino xapges 其中的dojo.xhrGet 和 dojo.xhrPost例子