锁定老帖子 主题:JS 异步按需载入和异步编程总结
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-05
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 授权: 共同创作2.0 - 作者: trydofor 本文使用了[[a9text => http://a9text.sf.net]]格式. 目标读者为,有一定js基础,并对异步按需载入有需求的人群. 0. 目录 ^^^^^^^ [[<=$INDEX]] 1. 为什么异步按需载入 ^^^^^^^^^^^^^^^^^^^^^ 在web应用上,经常会根据需要来载入不同的JS/CSS/TEXT/HTML等. 在粗放型web开发,被用户体验取代的今天,按需载入也被用来榨干代码中的油水. 之所以我过多的关注按需载入,是因为sourceforge.net的访问速度有点可怜. 而且我一直努力的a9text有太多的area需要实时载入parser和render. 开发和本地使用,使用了XMLHttpRequest同步,但web应用中同步就等于死机 曾经和JSI的金大卫调侃说:知道浏览器厂商,啥时候能改善同步的体验不? 异步按需载入迫在眉睫,但JSI又不适合a9text. JSI的着眼点在于已知,而a9text在于运行时和线程功能. 尽管老金告诉我JSI2.0瘦身版才5k,代码才500行. 无奈,只能自力更生 ... 2. 如何异步按需载入和异步编程 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ js不支持线程功能,更不用指望sleep和wait等功能.异步编程的不可预测性在js上徒增. (http://www.neilmix.com/narrativejs/doc/设想不错,大家可以学习下) 挣扎过程中,考虑过timeout和interval,但不是最佳,也不是有效的方法. 解铃还得系令人,着眼点还得回到XMLHttpRequest的使用上来. 为此,a9text废除了a9engine,写了个专一的a9loader,用来提供异步开发的模式. 首先亮相的是a9loader提供了以下2个异步载入和编程的方法. ........................................................... void A9Loader.asyncImportClass(String clzz) async import an js and export like java @param clzz (String) eg:'com.trydofor.a9text.parser.a9text' void A9Loader.runAfterImport(Function func) run the func when all class imported @param func (Function) ........................................................... asyncImportClass 用来 异步载入/初始化/包隔离/公共化 一个js类 runAfterImport 用来执行所有等待import完毕后的方法. ================== js : example ======================== A9Loader.asyncImportClass('com.trydofor.a9text.parser.a9text'); A9Loader.asyncImportClass('com.trydofor.a9text.render.html.a9text'); A9Loader.runAfterImport(function(){ for(var i=0; i<a9PreText.length;i++){ var a9dom = new A9Dom(null,A9Dom.type.root); //com.trydofor.a9text.A9Dom a9dom.setText(a9PreText[i]); a9dom.putInfo(A9Dom.type.root$path,A9Loader.getPagePath()); a9DomHtml[a9dom.getId()] = a9PreHtml[i]; new A9TextParser().parse(a9dom,function(){ new A9TextRender().render(a9dom,function(){ var a9htm = a9dom.getData(); var preHtml = a9DomHtml[a9dom.getId()]; var prePos = bodyHtml.indexOf(preHtml); var headPos = bodyHtml.lastIndexOf('<',prePos); var footPos = bodyHtml.indexOf('>',prePos+preHtml.length)+1; bodyHtml = bodyHtml.substring(0,headPos) + a9htm + bodyHtml.substr(footPos); if(document.body) document.body.innerHTML=""; document.write(bodyHtml); document.close(); }); }); } }); ======================================================== 上面的代码中,runAfterImport中还间接的调用了runAfterImport. 但结果都是缓存在一个队列中,等待import结束后顺序执行. 实现手法是这样的: 有一个task队列,里面有引用计数和几个队列. 发送一个async request的时候,计数加1,callback的时候,计数减1 同时呼叫一个检查计数的方法. 当最后一个callback执行时,计数等于0,于是开始处理各种队列. 3. 应用范围与不足 ^^^^^^^^^^^^^^^^^ 本应用属于另类,仅在特殊场合应用或学习使用, 一般的web开发,最好使用script tag或通常的ajax手法. 因为没有使用timeout和interval,框架完全基于一个基本假设, 就是所有async请求都能正常返回,如果其中有一个出现问题, runAfterImport中排队的方法将永远不被执行. 其中的危险,主要来自浏览器的缓存,网络条件. 异步JS开发,请尽量回避. 希望a9loader和本文对需要的人有帮助. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-03-05
没有明白为什么JSI不符合你的需求。。。
|
|
返回顶楼 | |
发表时间:2008-03-05
首先,得声明,JSI是个不错的东西,生命力很强.
之所以说JSI不适合a9text,其根本原因有下: 1. 代码包管理, 我喜欢用java中package的概念来管理脚本.尽管有点多此一举, 但这样做是有点好处的,而这点与JSI中包的定义是不一样的. 2. 运行时异步载入. JSI的$import的特点是,载入一个js就需要callback一次, 而a9text是运行时检测要载入的类,并全部载入后才可以执行. 如果使用JSI,基本上还需要写一个脚本管理器,并且编写代码 结构也变得复杂,难读,难维护,与其那样,不如定制一个'JSI' 3. 整体考虑. JSI的最简版,也是要500行,a9loader算上注释也500行,而且都是自身需要的代码. 在JSI1.0的时代,a9text就有自己的loader(a9engine),处于整体的考虑,还是用 自己的最合适,不至于JSI定位扩大了,我也更正扩大 其实,不管是JSI还是a9loader,出发点和原理都是一样的,处于学习的目的, 我选择了自主,绝对没有说JSI不好的意思. 不知楼上认同否 ^_^ |
|
返回顶楼 | |
发表时间:2008-03-05
1. jsi好像是可以做package的。只是也可以直接做脚本依赖。
2. 没有明白你的意思。你是指它的异步载入的api不符合你的需求么? |
|
返回顶楼 | |
发表时间:2008-03-07
再写下篇总结前,做个回复,我说的运行时异步载入是这样的:
1.载入/获得一段A9text文本. | V 2.异步载入a9textParser和xxxRender | V 3.parse过程中有xxxArea --->异步载入 xxxAreaParser --->(重复2.) | V 4.开始xxxRender | V 5.render过程中发现xxxArea --->异步载入 xxxAreaRender ---> (重复4.) | V 6.输出render结果 其中 3.和5.就是运行时异步载入的, 无法预先得知,所以不可以提前载入. 为了提高代码可读性,就出现了a9loader的框架来解决这样的问题. 知道论坛里高手比较多,这里献丑了,希望大家提提建议和改善意见. a9loader本身比较清晰,希望读过代码(包括JSI)的在回贴. |
|
返回顶楼 | |
发表时间:2008-03-08
i c.
你需要的是模块的动态载入(按需载入),类似于classloader。 就你的需求来说,似乎不需要命名空间管理(也就是,似乎你的import是把一个包内的名字全部导入到global上)。这较为接近我已经停止开发的老PIES的功能(除了我只用同步不用异步之外)。 假如确实如此,则你用importXXX的命名稍有误导。import通常指静态的名称导入而和模块加载并无必然联系(虽然有些语言中不是如此,但是至少java是这样)。如果只是加载,建议你把api改为A9Loader.load('...')。然后你的A9Loader.runAfterImport(function(){...})可以改成A9Loader.onload = function () {...} 跟网页编程一样了,呵呵。 JSI(以及PIES)的主要目标都包括了命名空间和名称间的依赖管理,而不是一种纯粹的加载模块管理。比如JSI处理名称(对象间)依赖或者是script文件的依赖,而不直接处理“包”(据我看,A9Loader的包实际上是一个命名的加载模块,而不是java中作为namespace的package)的依赖。 不过事实上,它们是可以提供直接处理包依赖这样的功能的,PIES的草案设计就包含了这样的设计。但是怎样设计比较合理是个费心的事情。 还有,你说“JSI的$import的特点是,载入一个js就需要callback一次”,这大概就是一个API限制,但是没有理由在原理上有这种限制(我觉得JSI原来的addScriptDepedency或许接近你的需求,除了他的单位是script file而不是你的命名过的包【模块】)。你可问问jindw现在jsi是否能满足你的需求,呵呵。 |
|
返回顶楼 | |
发表时间:2008-03-08
很感谢你的回复,今天是妇女节,差点累死我 ...
曾经和jindw简单的讨论过,但是JSI的定位和a9text不一样. 因此过多的让jindw关心a9text有点不合适,而且JSI2.0在耗很多心血. 代码是程序员最好的思想交流,我读了部分JSI代码, 借鉴一些合适的内容. 本文的目的主要是做个总结,让有特别需求的人少走弯路. 同时我也非常推荐使用JSI来解决JS开发带来的麻烦. 不过a9text的确比较特别(本位主义一下),算是另类应用. 关于方法命名,我暂时就不考虑修改啦,就张冠李戴凑合着用吧. runAfterImport的执行时机,有点特别,不同于onload. 主要是可能别多次暂停和继续,即在一个runAfterImport执行方法中,又异步载入了一个类. 这时候,下一个runAfterImport,就需要等到这个类初始化完成才执行. 而a9text中就大量使用了这样的调用. 然后,补充一点,a9loader也是要解决脚本(包)依赖关系的,在__info__.js中描述 (a9text的命名是python和java的混合体,比较乱) 之所以使用包,而不是直接释放到全局,是因为a9text里面的impl都是相同的命名. (算是自找麻烦) 比如. com.trydofor.a9text.render.html.a9text.A9TextRender 和 com.trydofor.a9text.render.dom.a9text.A9TextRender 就是不同的impl 所以需要使用包来隔离,这样切换impl比较方便,多个共存也容易. 这是根本原因. |
|
返回顶楼 | |
发表时间:2008-03-09
思考了一下,咱不能做得过且过的营生,还是修改了import
改成: void A9Loader.syncLoadClass(String clzz) sync import an js and export like java @param clzz (String) eg:'com.trydofor.a9text.parser.a9text' void A9Loader.asyncLoadClass(String clzz) async import an js and export like java @param clzz (String) eg:'com.trydofor.a9text.parser.a9text' void A9Loader.runAfterClassLoaded(Function func) run the func when all class imported @param func (Function) 我想这回能比较恰当些,看来论坛里讨论是很有积极意义的, 可惜,我发的帖子,只有福娃兄弟关注. 是我的帖子太水,还是没人关注... 学造自己的车,让别人去撞吧 |
|
返回顶楼 | |
发表时间:2008-03-30
“runAfterImport的执行时机,有点特别,不同于onload. ”
我觉得正好合适啊。因为document onload是要等待所有资源(比如图片)的onload完成之后才触发的,呵呵呵。 |
|
返回顶楼 | |
发表时间:2008-04-01
实际情况要复杂,不信,你可以访问下a9text.sf.net,看看源代码(右键即可以啦),基本上onload这个时间点,还没有载入大部分需要的js. onload不能解决的问题是,解析文档过程中,需要根据area名在配置文件中找到实现类并异步载入相关类,然后把结果合并到a9dom中,这个过程是比较难以把握的.
虽然异步载入,不是实际意义上的多线程,但是在这种竞争条件下,思考问题的方式和处理的方法,都会变得很诡异,要保证代码的可读性,是个比较棘手的问题,至少我在a9text的设计和编码过程中这样感想,js真是比较郁闷的事情 |
|
返回顶楼 | |