`
trydofor
  • 浏览: 147071 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

JS 异步按需载入和异步编程总结

阅读更多
JS 异步按需载入和异步编程总结
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- 授权: 共同创作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和本文对需要的人有帮助.
分享到:
评论
10 楼 hax 2008-04-02  
我是指runAfterImport的行为和onload比较类似,runAfterImport要等到所有依赖的包都载入完毕再执行,这与onload要等到所有资源都load完成才执行的意思是类似的。呵呵。
9 楼 trydofor 2008-04-01  
实际情况要复杂,不信,你可以访问下a9text.sf.net,看看源代码(右键即可以啦),基本上onload这个时间点,还没有载入大部分需要的js. onload不能解决的问题是,解析文档过程中,需要根据area名在配置文件中找到实现类并异步载入相关类,然后把结果合并到a9dom中,这个过程是比较难以把握的.

虽然异步载入,不是实际意义上的多线程,但是在这种竞争条件下,思考问题的方式和处理的方法,都会变得很诡异,要保证代码的可读性,是个比较棘手的问题,至少我在a9text的设计和编码过程中这样感想,js真是比较郁闷的事情
8 楼 hax 2008-03-30  
“runAfterImport的执行时机,有点特别,不同于onload. ”

我觉得正好合适啊。因为document onload是要等待所有资源(比如图片)的onload完成之后才触发的,呵呵呵。
7 楼 trydofor 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)

我想这回能比较恰当些,看来论坛里讨论是很有积极意义的,
可惜,我发的帖子,只有福娃兄弟关注.

是我的帖子太水,还是没人关注...
学造自己的车,让别人去撞吧
6 楼 trydofor 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比较方便,多个共存也容易.
这是根本原因.
5 楼 hax 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是否能满足你的需求,呵呵。
4 楼 trydofor 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)的在回贴.



3 楼 hax 2008-03-05  
1. jsi好像是可以做package的。只是也可以直接做脚本依赖。
2. 没有明白你的意思。你是指它的异步载入的api不符合你的需求么?
2 楼 trydofor 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不好的意思.

不知楼上认同否 ^_^
1 楼 hax 2008-03-05  
没有明白为什么JSI不符合你的需求。。。

相关推荐

    如何让动态插入的javascript脚本代码跑起来

    在JavaScript编程中,动态插入脚本是一种常见的技术,用于在页面加载后或者根据某些条件按需加载外部的JavaScript文件。这种技术在处理大型应用、优化页面性能或实现异步加载时非常有用。本文将详细介绍如何让动态...

    IE WebBrowser编程技巧

    本WebBrowser编程技术包括Delphi、C#、VC++、VB等编程资料的集合,其中的 实例大多以Delphi为示例讲解,Delphi7 IDE开发环境。 IE_WebBrowser编程技巧 修改WebBrowser的header信息? Delphi查看...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part1.rar

     7.1.2 JavaScript和XMLHttpRequest对象   7.1.3 XML   7.1.4 一个可重用的对象   7.1.5 Ajax是正确的选择吗   7.2 为什么Ajax会破坏网站及如何解决   7.2.1 依赖JavaScript生成内容   7.2.2 ...

    基于JQuery脚本库的动态效果的设计与实现.pdf

    JQuery是一个轻量级的JavaScript函数库,能够让开发者在网页上快速简单地操作HTML文档添加动画和进行Ajax异步交互,从而提高开发者的编程效率。 在设计静态网页效果时,采用隐藏显示方法实现滑动门效果,采用计时...

    ASP.NET高级编程:为校园BBS用户注册提供无刷新验证.pptx

    AJAX的核心是JavaScript对象XMLHttpRequest,该对象是一种支持异步请求的技术,用户可以使用该对象向服务器提出请求并处理响应,并且还不会影响客户端的信息通信。 ;ASP.NET3.5 和AJAX ASP.NET 3.5之前,ASP.NET自身...

    AJAX技术在Web页面开发中的应用.pdf

    它结合了JavaScript技术、XML、 DOM 等编程技术,可以使得客户端和服务器端交换数据的响应更实时,而不需要每次都重新载入整个页面。 AJAX的工作原理是将JavaScript、XML、DOM等技术组合起来,共同协作发挥各自的...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part3.rar

     7.1.2 JavaScript和XMLHttpRequest对象   7.1.3 XML   7.1.4 一个可重用的对象   7.1.5 Ajax是正确的选择吗   7.2 为什么Ajax会破坏网站及如何解决   7.2.1 依赖JavaScript生成内容   7.2.2 ...

    [JavaScript.DOM高级程序设计](加)桑贝斯.扫描版.part2.rar

     7.1.2 JavaScript和XMLHttpRequest对象   7.1.3 XML   7.1.4 一个可重用的对象   7.1.5 Ajax是正确的选择吗   7.2 为什么Ajax会破坏网站及如何解决   7.2.1 依赖JavaScript生成内容   7.2.2 ...

    13-Ajax中级.pptx

    在JavaScript中,Ajax(Asynchronous ...总的来说,理解和掌握如何创建Ajax对象、建立服务器连接、发送请求以及监控请求状态,是进行Ajax编程的基础。通过这些知识点,开发者可以构建出高效、交互性强的Web应用。

    ajax、spring、ejb试题

    Spring 提供了一个全面的编程和配置模型,对服务层的支持包括事务管理、数据访问集成等。它推崇 DI(依赖注入)和 AOP(面向切面编程),并提供了丰富的 MVC(模型-视图-控制器)框架。Spring 还支持多种持久层技术...

    详解Js中的模块化是如何实现的

    总结来说,JavaScript 的模块化通过解决代码组织、复用和作用域隔离等问题,提升了代码质量,简化了项目管理。随着技术的发展,各种模块化方案的出现和改进,使得在JavaScript开发中实现模块化变得越来越简单和高效...

    JQUERY速成教程

    【jQuery 速成教程】是面向初学者的编程教程,旨在快速引导学习者掌握这个流行的JavaScript库。jQuery简化了HTML文档遍历、事件处理、动画和Ajax交互等任务,使得前端开发更为高效。通过本教程,你可以深入了解...

    flex3的cookbook书籍完整版dpf(包含目录)

    在ActionScript和JavaScript之间跨脚本操作 23.14节.本地SQL数据库 23.15节.检测和监控网络连接 23.16节.检测用户是否在线 23.17节.创建系统托盘图标 第二十四章. FlexUnit单元测试(742) 24.1节. 创建应用FlexUnit...

    ASP.NET.4揭秘 卷2

    n436 缓存动态载入的用户控件 n44 使用数据源缓存 n441 使用绝对缓存过期策略 n442 使用弹性缓存过期策略 n443 使用ObjectDataSource控件缓存 n444 使用XmlDataSource控件缓存 n445 创建DataSource控件键依赖 n45 ...

    ActionScript开发技术大全

    10.2.10异步异常事件ErrorEvent、IOErrorEvent、SecurityErrorEvent 218 10.2.11全屏事件FullScreenEvent 219 10.3虚拟键盘示例 220 10.4小结 224 .第11章ActionScript3.0可视对象 225 11.1可视对象类DisplayObject ...

    AngularJS 2.0新特性有哪些

    5. 模板和数据绑定:模板和数据绑定在Angular 2.0中得到了深度整合,使得模板编译过程异步化,提升了应用的响应速度。同时,模板指令分为组件指令、装饰指令和模板指令,提供了更多样化的模板操作和复用方式。 6. ...

    KODExplorer 芒果云-资源管理器

    - 权限按功能划分成颗粒,可以任意配置,例如普通使用者、游客等 - 搜索:支持递归搜索,可选择是否搜索文件内容。 - 增加桌面自定义壁纸。 - 皮肤优化 ok 多色彩支持。 - 应用商店,root用户可以管理应用。安装、...

    XML轻松学习手册--XML肯定是未来的发展趋势,不论是网页设计师还是网络程序员,都应该及时学习和了解

    面向对象的思想方法已经非常流行了,在编程语言(例如java,js)中,都运用面向对象的编程思想。在XML中,就是要将网页也作为一个对象来操作和控制,我们可以建立自己的对象和模板。与对象进行交流,如何命令对象,...

Global site tag (gtag.js) - Google Analytics