Posts Tagged ‘javascript’

上篇中外链的一篇分享:http://limu.javaeye.com/blog/840159提到了依赖循环的问题,即模块互相依赖形成了死循环。
举例说明:a->b、b->c、c->a。这种依赖是没法执行的,如果运行的话会引发无限死循环,必须预防。可以考虑的方案无非定义时检测(链接中limu中的方案),或者使用时检测,两者大同小异。
伪代码:
//检测是否有循环依赖
function checkRecursion(list) {
var history = {},
stack;
//遍历需要异步加载的模块列表,每个模块深度遍历检测自己的依赖,出现过的说明此回路已检测过无需重复,记录在history中
list.forEach(function(mod) {
stack = [];
if(!history[mod.name]) {
history[mod.name] = 1;
scanRecursion(mod, {});
}
});
//每个模块深度遍历过程中,边记录边遍历,发现重复的说明出现循环回路,报异常
function scanRecursion(mod, has) {
if(mod && mod.deps) {
stack.push(mod.name);
mod.deps.forEach(function(dep) {
if(has[dep])…

从按需装载到并行异步,再至递归依赖和串行异步,javascript的潜力也在被开发者们尽情地挖掘。最初是谁先提出来这个的?老道?这个周末也尝试实现了下,这种思维模式的确很让人受到启发。
按需装载
数年前web2.0刚刚起步之时,按需装载首先被提出,这个思维比较简单:只有当用到某个js(确切说法应该是模块)时才会去装载它。举个例子而言,根据cookie确定用户有没有登录,有的话才去ajax请求用户信息并且显示在页面上的某个地方,没有的话不请求也不显示。这是很普遍的技术了,没什么好多说的。
并行异步
随后请求被细分,可能我要执行某个操作的时候,需要加载2个甚至多个js的情况,那么这个加载过程肯定是并行的。没理由先加载一个成功再加载另外一个再成功后才能执行操作——这是浪费时间。
并行异步中唯一要解决的就是同时并发2个请求时,客户端如何判断2个请求全部加载执行完成。很简单,为这个操作设一个计数器,值为依赖请求的个数(如2)。每个依赖请求加载成功后回调计数器自减,当计数器归零时说明全部加载完成。
这个算法很简单,但是需要考虑交叉的情况。即操作1请求了模块a和模块b,操作2请求了模块b和模块c的时候,共用一个模块b的请求要写好。
递归依赖
还有更复杂的情况。比如操作1依赖模块a和b,操作2依赖模块b和c,但是模块c依赖模块d,这该如何是好?
此时需要递归计算依赖,将每个操作所需要的依赖统统找出来,再并发异步即可。
串行异步
好了,真正的难点来了,如果还记得计算机操作系统中的线程的概念的话,这里将触及到类似线程睡眠的东西。
操作1依赖模块a和b,操作2依赖模块b和c,c又依赖d,d再依赖a。这可不是简单的一次性并发请求的问题了。试问:假如使用并发异步的话,模块d可能在模块a之前被加载进来并执行,那么这将会是个错误,用户会在他的浏览器上看到一个大大的叉。
但是我们又不想死板地先加载a,等a加载完成后再去并发。我们想实现串行异步,这该如何呢?
很简单,在d加载完成后先“审时度势”,查看下a有没有加载并执行好。当a已经好了的时候,我们尚可无所顾忌地执行d;而当尚未完成时将d休眠,并且在a的加载成功回调函数中加入一个新的回调:去唤醒d。
完成了这部,可算是实现了串行异步的一半了。还有另一半,即是串行异步的交叉,多个模块依赖多个模块并且彼此之间有交叉的情况出现,这和上面并发异步的交叉类似,需要递归计算并使用计数器。原理就说到这里,具体的实现就不贴了。
因为这些将是“达克斯”可能在d2上的演讲提到的东西,暂且保密。
防止死循环
http://limu.javaeye.com/blog/840159
提到的死循环很给力,虽然属设计上的失误,但合作开发难免会出现,应预防之。抽空补上。
附:已补上,下一篇就是。

三月 5th, 2010

[译]理解删除

2 Comments, 前端开发, by army8735.

http://perfectionkills.com/understanding-delete/
原文作者是在读《Object-Oriented Javascript》的Function章节后有感,写下的一篇博文。
书中有一句话:function其实就是一个普通变量——它可以被复制到另一个变量中而不会被删除。如果这样解释的话,这里有个例子:
//army注:这一源代码片段是在Firebug下的Console控制台运行的,放在页面中需改写
var sum = function(a, b) {return a + b;}
var add = sum;
delete sum;
true
typeof sum;
“undefined”
忽略代码中省略的两个分号,你注意到这个代码片段的问题了吗?按那句话所说,删除sum不应该成功;delete语句返回的值不可能是true;typeof sum的结果不会是”undefined”。可是事实却非如此,所有的这一切都是因为:Javascript中不可能删除变量。至少不能以这种方式删除。
这是为什么呢?
要回答这个问题,我们需要理解delete操作符是怎么运作的:即什么可以删除、什么不可以删除、为什么?
原理
我们为什么可以这样删除对象的属性?
var o = {…