论坛首页 Web前端技术论坛

Ext 2.0 for JSVM

浏览 39208 次
该帖已经被评为精华帖
作者 正文
   发表时间:2007-10-24  
我看就应该统一一个标准,比如这个$import就当成标准来用挺好的, 我自己以前都写_import的, 现在改了.
0 请登录后投票
   发表时间:2007-10-24  
wch3116 写道
解析Ext模块之间依赖关系的工具非常简陋,几乎没有共享出来的价值,呵呵。
大概原理是:通过正则表达式匹配出当前模块的代码中引用了哪些其它 Ext 模块的名称,然后在文件头部生成 $import 语句。
但是存在一些地方是需要手工调整。因为模块之间文件头部“静态”import 不能形成回环,循环import会造成 jsvm engine 的“死锁”。所以必须将一些造成回环的依赖链打断,调整为运行时动态的import。
启用过smartloader的页面,不会存在多次xhr交互的情况。当然这并不否定import支持多个动态参数是一个好的办法。


既然称之为smartloader,为啥不花点时间写个算法,把出现回环的情况自动打断,基于我写Java2Script ClassLoader的经验,只要能够写一个树状的网络结构,从上而下地检索环路,但出现环路,打断其中一个依赖,继续加载,直到所需的所有文件加载完毕。思路清晰的话,可能花一到两三人周就应该可以稳定下来。虽然ClassLoader出发点不一样,也可以参考以下:
http://j2s.svn.sourceforge.net/viewvc/j2s/trunk/sources/net.sf.j2s.java.core/src/java/lang/ClassLoader.js?view=markup


对于第三方的js库,估计也没有好办法来生成$import,不像dojo。对于Java2Script下的类,由于*.js由编译器自动生成,所以$import相关也自动生成了。
0 请登录后投票
   发表时间:2007-10-24  
wch3116 写道
再谈 js 代码的加载问题

我们在开发一个 rich javascript 应用时,一般会遇到两件事情:
1. 代码应该按功能、模块或其它合理粒度方式切分到多个文件单元中,以便于管理维护和重用。
2. 系统运行时,应该按需加载所要执行的模块代码。因为将程序所有可能要用到的模块都事先全部加载进来听起来并不是一个好主意。

由于 js 代码因为设计上的需要被切分成多个文件,XMLHttpRequest 同步操作造成浏览器阻塞,如果网络不畅,这个过程时间长的话,浏览器的现象是假死(没有响应了)
传统的 <script> 标签方式加载多个 js 文件显然没有出现上面的问题,于是异步加载方案又被重新考虑进来。

其实在比较早(大概是2004年)的一次讨论中,有位网友提到了类似的问题,他提出了一个“异步加载”的方案。我们对此也做了不短时间的讨论。
但我一直坚持以为解决问题的方向不应该是“同步”和“异步”之间的选择问题。

“异步” 不仅打乱了开发人员的一般习惯思维方式,同时也改变了程序顺序加载执行最朴素的规律。
对于模块之间的静态依赖,或者程序对模块的静态需求,采用预加载的方式,然后通过事件侦听或者回调程序入口来继续加载后的的程序执行尚且可以。
但这些依赖或者需求是程序运行时动态决定的,而采用异步的方式肯定造成程序分支增多,增加了系统的复杂性。

而这一切就是为了解决浏览器同步加载多个文件时而造成的“假死”?
浏览器假死不是“同步”这个模式(概念)本身的错误。而是现有的环境(条件)造成的。
试想,如果仍然是同步阻塞,但没有造成浏览器假死是不是也能接受?
所以,我觉得可以通过其它方式来解决这个问题。

本地浏览模式或者网络相当顺畅的情况下,我们几乎不用太担心浏览器因为这种原因而造成的假死。
如果能为页面为单位,记录每个页面所需要的模块(代码),当下一次程序被运行时能提前将这些代码通过非阻塞的方式预加载到缓存(内存)中,
之后的代码加载都在内存中进行,虽然还是同步方式,但没有网络IO的操作,问题是不是解决了?

jsvm 2.06 之后的 smartloader 模块(扩展)就是基于这个原理工作的。
开发人员依然只需考虑设计层面的问题,而不必去关心过多加载次数造成的麻烦。


无论预加载还是异步按需加载,如果控制粒度都是一个个问题。粒度的控制不应该是开发阶段作考虑,应该是在部署阶段进行配置的(当然ClassLoader需要提供控制粒度的配置),有专业人士进行分包打包并作优化。

异步按需加载并没有想象中的那么复杂,如果你已经完成一个ClassLoader,那么给ClassLoader一个改造,提供加载完毕的callback,那么可以用类似如下代码完成异步调用:
ClassLoader.loadClass ("org.blahblah.HelloWorld", function () {
org.blahblah.HelloWorld.sayHi();
));
或者
ClassLoader.loadClass (["org.blahblah.HelloWorld","org.blahblah.utils.StringUtils"], function () {
var s = org.blahblah.HelloWorld.sayHi();
var k = org.blahblah.utils.StringUtils (s);
));

在Java2Script的支持下,可以使用Java的匿名类作为相关callback类,还可以跨closure传递相关的变量对象,这样的话,对开发者不会有太大的异步恐惧的。

Java2Script( http://j2s.sourceforge.net/ )的ClassLoader支持加载粒度配置和异步按需加载(当然同步加载也是支持的,不过默认不是这个模式),而且支持XHR和SCRIPT的方式,可以从多个服务器上下载编译得到的*.js文件。有兴趣研究的话可以下载研究一下:
http://downloads.sourceforge.net/j2s/j2slib-1.0.0-v20071002.zip
http://sourceforge.net/project/showfiles.php?group_id=155436

BTW:个人认为,需要专门的服务器端*.jsp或者servlet协助ClassLoader完成相关功能,是一个非常糟糕的设计。
0 请登录后投票
   发表时间:2007-10-24  
zhourenjian 写道
wch3116 写道
解析Ext模块之间依赖关系的工具非常简陋,几乎没有共享出来的价值,呵呵。
大概原理是:通过正则表达式匹配出当前模块的代码中引用了哪些其它 Ext 模块的名称,然后在文件头部生成 $import 语句。
但是存在一些地方是需要手工调整。因为模块之间文件头部“静态”import 不能形成回环,循环import会造成 jsvm engine 的“死锁”。所以必须将一些造成回环的依赖链打断,调整为运行时动态的import。
启用过smartloader的页面,不会存在多次xhr交互的情况。当然这并不否定import支持多个动态参数是一个好的办法。


既然称之为smartloader,为啥不花点时间写个算法,把出现回环的情况自动打断,基于我写Java2Script ClassLoader的经验,只要能够写一个树状的网络结构,从上而下地检索环路,但出现环路,打断其中一个依赖,继续加载,直到所需的所有文件加载完毕。思路清晰的话,可能花一到两三人周就应该可以稳定下来。虽然ClassLoader出发点不一样,也可以参考以下:
http://j2s.svn.sourceforge.net/viewvc/j2s/trunk/sources/net.sf.j2s.java.core/src/java/lang/ClassLoader.js?view=markup


对于第三方的js库,估计也没有好办法来生成$import,不像dojo。对于Java2Script下的类,由于*.js由编译器自动生成,所以$import相关也自动生成了。


我觉得这里存在一些误解,我大致理解你的意思,但smartloader加载代码的时候不存在回环的问题。
我前面说的是回环是指模块文件头部的“静态”$import语句使用不当,导致模块“编译时”循环依赖,和smartloader没有关系。

例如,两个文件互相包含:

文件 A:
#include B;

文件 B:
#include A;

或者两个类互相继承依赖:

class A extends B {

}

class B extends A {

}

上面这些都是设计上的逻辑错误。

jsvm 的 engine 中有一个 lock 对象,用于防止这种意外的发生

我个人推荐尽量减少编译时的依赖,尽量使用运行时的动态依赖。

jsvm 在处理 $import 造成的回环,面临两个选择。
发现回环,抛出异常中断加载,或者忽略继续运行(因为头部的$import进来的模块不一定是编译时就需要的,也许是运行时才用到的)
最后jsvm暂时选择了前者。这个矛盾现在依然存在,是一个如何取舍问题,没有绝对的对与错。
0 请登录后投票
   发表时间:2007-10-24  
直接再代码中使用$import,可以简单的描述一个装在前依赖。
但是我们还可能涉及一种装在后依赖,就是脚本运行过程中可能使用的的东西。

JSI中,我们就可以定义循环依赖,定义语法更加严谨一些,当能,也显得有点复杂。

包定义文件:
this.addScript("clazz-a.js",["ClassA","methodA"]);
this.addScript("clazz-b.js",["ClassB","methodB","andOtherObject"]);

//装载前(装在期)依赖
this.addScriptDependence("clazz-b.js","clazz-a.js",true);
//装载后(运行时)依赖
this.addScriptDependence("clazz-a.js","clazz-b.js",false);
0 请登录后投票
   发表时间:2007-10-24  
zhourenjian 写道
wch3116 写道
再谈 js 代码的加载问题

我们在开发一个 rich javascript 应用时,一般会遇到两件事情:
1. 代码应该按功能、模块或其它合理粒度方式切分到多个文件单元中,以便于管理维护和重用。
2. 系统运行时,应该按需加载所要执行的模块代码。因为将程序所有可能要用到的模块都事先全部加载进来听起来并不是一个好主意。

由于 js 代码因为设计上的需要被切分成多个文件,XMLHttpRequest 同步操作造成浏览器阻塞,如果网络不畅,这个过程时间长的话,浏览器的现象是假死(没有响应了)
传统的 <script> 标签方式加载多个 js 文件显然没有出现上面的问题,于是异步加载方案又被重新考虑进来。

其实在比较早(大概是2004年)的一次讨论中,有位网友提到了类似的问题,他提出了一个“异步加载”的方案。我们对此也做了不短时间的讨论。
但我一直坚持以为解决问题的方向不应该是“同步”和“异步”之间的选择问题。

“异步” 不仅打乱了开发人员的一般习惯思维方式,同时也改变了程序顺序加载执行最朴素的规律。
对于模块之间的静态依赖,或者程序对模块的静态需求,采用预加载的方式,然后通过事件侦听或者回调程序入口来继续加载后的的程序执行尚且可以。
但这些依赖或者需求是程序运行时动态决定的,而采用异步的方式肯定造成程序分支增多,增加了系统的复杂性。

而这一切就是为了解决浏览器同步加载多个文件时而造成的“假死”?
浏览器假死不是“同步”这个模式(概念)本身的错误。而是现有的环境(条件)造成的。
试想,如果仍然是同步阻塞,但没有造成浏览器假死是不是也能接受?
所以,我觉得可以通过其它方式来解决这个问题。

本地浏览模式或者网络相当顺畅的情况下,我们几乎不用太担心浏览器因为这种原因而造成的假死。
如果能为页面为单位,记录每个页面所需要的模块(代码),当下一次程序被运行时能提前将这些代码通过非阻塞的方式预加载到缓存(内存)中,
之后的代码加载都在内存中进行,虽然还是同步方式,但没有网络IO的操作,问题是不是解决了?

jsvm 2.06 之后的 smartloader 模块(扩展)就是基于这个原理工作的。
开发人员依然只需考虑设计层面的问题,而不必去关心过多加载次数造成的麻烦。


无论预加载还是异步按需加载,如果控制粒度都是一个个问题。粒度的控制不应该是开发阶段作考虑,应该是在部署阶段进行配置的(当然ClassLoader需要提供控制粒度的配置),有专业人士进行分包打包并作优化。

异步按需加载并没有想象中的那么复杂,如果你已经完成一个ClassLoader,那么给ClassLoader一个改造,提供加载完毕的callback,那么可以用类似如下代码完成异步调用:
ClassLoader.loadClass ("org.blahblah.HelloWorld", function () {
org.blahblah.HelloWorld.sayHi();
));
或者
ClassLoader.loadClass (["org.blahblah.HelloWorld","org.blahblah.utils.StringUtils"], function () {
var s = org.blahblah.HelloWorld.sayHi();
var k = org.blahblah.utils.StringUtils (s);
));

在Java2Script的支持下,可以使用Java的匿名类作为相关callback类,还可以跨closure传递相关的变量对象,这样的话,对开发者不会有太大的异步恐惧的。

Java2Script( http://j2s.sourceforge.net/ )的ClassLoader支持加载粒度配置和异步按需加载(当然同步加载也是支持的,不过默认不是这个模式),而且支持XHR和SCRIPT的方式,可以从多个服务器上下载编译得到的*.js文件。有兴趣研究的话可以下载研究一下:
http://downloads.sourceforge.net/j2s/j2slib-1.0.0-v20071002.zip
http://sourceforge.net/project/showfiles.php?group_id=155436


你上面的异步例子都是针对加载“静态依赖的模块”的。

对于动态加载模块采用异步的方式带来的复杂和不优雅是随着嵌套层数几何增长的,当然,设计上采用一些技巧可以避免这种情况的恶化。对于异步带来的问题我并非只靠臆想,多年js异步编程经验了让我选择只在数据交互上采用异步方式,而在代码装载上尽可能的避免。并非不能实现,而是觉得不应该这样实现,原因前面提到过。(当然,很多时候经验不一定对)

zhourenjian 写道

BTW:个人认为,需要专门的服务器端*.jsp或者servlet协助ClassLoader完成相关功能,是一个非常糟糕的设计。


这句话我不太理解。

jsvm2 本身被设计成功能完备且完全脱离对服务器端的依赖(不需要任何服务端的动态支持),jsvm的classloader本身也提供了lib批量加载方式用来优化加载性能。
smartloader 是一个额外的扩展模块(可选),它需要服务端动态语言的支持,例如:jsp,asp (php,perl尚未完成),使用jsp而不用servlet或者filter,目的是为了部署简单,不需要额外在服务器端做其它的配置。

smartloader的启用方式是在jsvm的环境中配置到modules参数中:
<script src="jsvm2目录/jsre.js" modules="smartloader"></script>


j2s 需要 java/servlet 支持吗?


0 请登录后投票
   发表时间:2007-10-25  
wch3116 写道
zhourenjian 写道
wch3116 写道
解析Ext模块之间依赖关系的工具非常简陋,几乎没有共享出来的价值,呵呵。
大概原理是:通过正则表达式匹配出当前模块的代码中引用了哪些其它 Ext 模块的名称,然后在文件头部生成 $import 语句。
但是存在一些地方是需要手工调整。因为模块之间文件头部“静态”import 不能形成回环,循环import会造成 jsvm engine 的“死锁”。所以必须将一些造成回环的依赖链打断,调整为运行时动态的import。
启用过smartloader的页面,不会存在多次xhr交互的情况。当然这并不否定import支持多个动态参数是一个好的办法。


既然称之为smartloader,为啥不花点时间写个算法,把出现回环的情况自动打断,基于我写Java2Script ClassLoader的经验,只要能够写一个树状的网络结构,从上而下地检索环路,但出现环路,打断其中一个依赖,继续加载,直到所需的所有文件加载完毕。思路清晰的话,可能花一到两三人周就应该可以稳定下来。虽然ClassLoader出发点不一样,也可以参考以下:
http://j2s.svn.sourceforge.net/viewvc/j2s/trunk/sources/net.sf.j2s.java.core/src/java/lang/ClassLoader.js?view=markup


对于第三方的js库,估计也没有好办法来生成$import,不像dojo。对于Java2Script下的类,由于*.js由编译器自动生成,所以$import相关也自动生成了。


我觉得这里存在一些误解,我大致理解你的意思,但smartloader加载代码的时候不存在回环的问题。
我前面说的是回环是指模块文件头部的“静态”$import语句使用不当,导致模块“编译时”循环依赖,和smartloader没有关系。

例如,两个文件互相包含:

文件 A:
#include B;

文件 B:
#include A;

或者两个类互相继承依赖:

class A extends B {

}

class B extends A {

}

上面这些都是设计上的逻辑错误。

jsvm 的 engine 中有一个 lock 对象,用于防止这种意外的发生

我个人推荐尽量减少编译时的依赖,尽量使用运行时的动态依赖。

jsvm 在处理 $import 造成的回环,面临两个选择。
发现回环,抛出异常中断加载,或者忽略继续运行(因为头部的$import进来的模块不一定是编译时就需要的,也许是运行时才用到的)
最后jsvm暂时选择了前者。这个矛盾现在依然存在,是一个如何取舍问题,没有绝对的对与错。


A.js:
一个方法中调用了new B();
B.js:
一个方法中调用了new A();
那么A.js中应该$import B,而B.js中应该$import A。这就是一个回环。如果以A为入口,当然不需要在B中$import A,则不存在回环;反之也一样。但是作为类库很难避免究竟以A为入口还是以B为入口吧。如果避免不了回环,那打破回环继续加载,可能会更好。
0 请登录后投票
   发表时间:2007-10-25  
wch3116 写道
zhourenjian 写道
wch3116 写道
再谈 js 代码的加载问题

我们在开发一个 rich javascript 应用时,一般会遇到两件事情:
1. 代码应该按功能、模块或其它合理粒度方式切分到多个文件单元中,以便于管理维护和重用。
2. 系统运行时,应该按需加载所要执行的模块代码。因为将程序所有可能要用到的模块都事先全部加载进来听起来并不是一个好主意。

由于 js 代码因为设计上的需要被切分成多个文件,XMLHttpRequest 同步操作造成浏览器阻塞,如果网络不畅,这个过程时间长的话,浏览器的现象是假死(没有响应了)
传统的 <script> 标签方式加载多个 js 文件显然没有出现上面的问题,于是异步加载方案又被重新考虑进来。

其实在比较早(大概是2004年)的一次讨论中,有位网友提到了类似的问题,他提出了一个“异步加载”的方案。我们对此也做了不短时间的讨论。
但我一直坚持以为解决问题的方向不应该是“同步”和“异步”之间的选择问题。

“异步” 不仅打乱了开发人员的一般习惯思维方式,同时也改变了程序顺序加载执行最朴素的规律。
对于模块之间的静态依赖,或者程序对模块的静态需求,采用预加载的方式,然后通过事件侦听或者回调程序入口来继续加载后的的程序执行尚且可以。
但这些依赖或者需求是程序运行时动态决定的,而采用异步的方式肯定造成程序分支增多,增加了系统的复杂性。

而这一切就是为了解决浏览器同步加载多个文件时而造成的“假死”?
浏览器假死不是“同步”这个模式(概念)本身的错误。而是现有的环境(条件)造成的。
试想,如果仍然是同步阻塞,但没有造成浏览器假死是不是也能接受?
所以,我觉得可以通过其它方式来解决这个问题。

本地浏览模式或者网络相当顺畅的情况下,我们几乎不用太担心浏览器因为这种原因而造成的假死。
如果能为页面为单位,记录每个页面所需要的模块(代码),当下一次程序被运行时能提前将这些代码通过非阻塞的方式预加载到缓存(内存)中,
之后的代码加载都在内存中进行,虽然还是同步方式,但没有网络IO的操作,问题是不是解决了?

jsvm 2.06 之后的 smartloader 模块(扩展)就是基于这个原理工作的。
开发人员依然只需考虑设计层面的问题,而不必去关心过多加载次数造成的麻烦。


无论预加载还是异步按需加载,如果控制粒度都是一个个问题。粒度的控制不应该是开发阶段作考虑,应该是在部署阶段进行配置的(当然ClassLoader需要提供控制粒度的配置),有专业人士进行分包打包并作优化。

异步按需加载并没有想象中的那么复杂,如果你已经完成一个ClassLoader,那么给ClassLoader一个改造,提供加载完毕的callback,那么可以用类似如下代码完成异步调用:
ClassLoader.loadClass ("org.blahblah.HelloWorld", function () {
org.blahblah.HelloWorld.sayHi();
));
或者
ClassLoader.loadClass (["org.blahblah.HelloWorld","org.blahblah.utils.StringUtils"], function () {
var s = org.blahblah.HelloWorld.sayHi();
var k = org.blahblah.utils.StringUtils (s);
));

在Java2Script的支持下,可以使用Java的匿名类作为相关callback类,还可以跨closure传递相关的变量对象,这样的话,对开发者不会有太大的异步恐惧的。

Java2Script( http://j2s.sourceforge.net/ )的ClassLoader支持加载粒度配置和异步按需加载(当然同步加载也是支持的,不过默认不是这个模式),而且支持XHR和SCRIPT的方式,可以从多个服务器上下载编译得到的*.js文件。有兴趣研究的话可以下载研究一下:
http://downloads.sourceforge.net/j2s/j2slib-1.0.0-v20071002.zip
http://sourceforge.net/project/showfiles.php?group_id=155436


你上面的异步例子都是针对加载“静态依赖的模块”的。

对于动态加载模块采用异步的方式带来的复杂和不优雅是随着嵌套层数几何增长的,当然,设计上采用一些技巧可以避免这种情况的恶化。对于异步带来的问题我并非只靠臆想,多年js异步编程经验了让我选择只在数据交互上采用异步方式,而在代码装载上尽可能的避免。并非不能实现,而是觉得不应该这样实现,原因前面提到过。(当然,很多时候经验不一定对)

zhourenjian 写道

BTW:个人认为,需要专门的服务器端*.jsp或者servlet协助ClassLoader完成相关功能,是一个非常糟糕的设计。


这句话我不太理解。

jsvm2 本身被设计成功能完备且完全脱离对服务器端的依赖(不需要任何服务端的动态支持),jsvm的classloader本身也提供了lib批量加载方式用来优化加载性能。
smartloader 是一个额外的扩展模块(可选),它需要服务端动态语言的支持,例如:jsp,asp (php,perl尚未完成),使用jsp而不用servlet或者filter,目的是为了部署简单,不需要额外在服务器端做其它的配置。

smartloader的启用方式是在jsvm的环境中配置到modules参数中:
<script src="jsvm2目录/jsre.js" modules="smartloader"></script>


j2s 需要 java/servlet 支持吗?




不太熟悉相对“静态依赖”的“动态依赖”是什么一个概念。
ClassLoader.loadClass ("org.blahblah.HelloWorld", function () {
org.blahblah.HelloWorld.sayHi();
));
如果在加载org.blahblah.HelloWorld对应的*.js文件过程中发现,该文件还依赖于其他类或者*.js,则ClassLoader会继续加载*.js文件,指导所有相关依赖全部满足,这个时候才会调用org.blahblah.HelloWorld.sayHi(),从而确保代码正确性。

“嵌套层数几何增长”是一个问题,看开发人员如何控制层数了。如果把callback当作一个类来设计的话,层数还是可以控制得比较得体。(对于我来说,Java的匿名类在嵌套层数增长上并没有给我带来太多困惑。)

异步交互,对javascript来说确实是一个难题。如果数据还跟着异步的数据流转的话,也会更繁琐。

貌似由于看到jsvm2的smartloader代码里有几行和jsp相关的代码,以及看到有*.jsp和*.html,所以就来了个“BTW”,没注意到这个是一个可选模块。

j2s的classloader和jsp/servlet无关,所有编译打包的*.js可以独立加载或者本地加载,需要和服务器打交道的会通过XHR调用或者Simple RPC调用。
0 请登录后投票
   发表时间:2007-10-25  
jindw 写道
直接再代码中使用$import,可以简单的描述一个装在前依赖。
但是我们还可能涉及一种装在后依赖,就是脚本运行过程中可能使用的的东西。

JSI中,我们就可以定义循环依赖,定义语法更加严谨一些,当能,也显得有点复杂。

包定义文件:
this.addScript("clazz-a.js",["ClassA","methodA"]);
this.addScript("clazz-b.js",["ClassB","methodB","andOtherObject"]);

//装载前(装在期)依赖
this.addScriptDependence("clazz-b.js","clazz-a.js",true);
//装载后(运行时)依赖
this.addScriptDependence("clazz-a.js","clazz-b.js",false);


装载前后的代码调用如何控制呢?机制如何呢?
0 请登录后投票
   发表时间:2007-10-25  
JSI 依赖的实现和其他框架是有很大不同的。
依赖不是直接在脚本中通过import定义,而是在包描述脚本中定义。

装载前可以通过包描述信息计算出装在资源清单和装载顺序。

这样做初衷是实现被管理脚本的框架无侵入性。
后来发现,这样的做法正好方便于实现脚本装载的仍外两种方式:
异步装在和延迟同步装载。
http://jindw.iteye.com/blog/66702
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics