复杂的实现是为了复杂的应用而设计的

之前写过一篇博文——《写一个事件队列操作函数》。

觉得catchen对异步事件队列相关的实现过于复杂,且并不易用。于是根据自己的理解,写了个很简单的辅助方法。 

并且当时对此颇为得意。

这几天看了相关的视频和slide才知道,为什么他实现的这么复杂并且直接使用的时候也不好用。

很简单,复杂的实现是为了复杂的应用而设计的。它处理更多的情况,当你不了解的时候,一般总难以理解为什么。

而使用麻烦并不真的是难用,只是在错误的地方进行了应用才会有这种感觉。。

视频在此《复杂Ajax应用开发模式》 

Slide在此《JavaScript Patterns》 

posted @ 2011-01-18 19:08 Akecn 阅读(52) 评论(0) 编辑

360浏览器下加入收藏夹功能失效的问题

测试同学那边提交了一个bug,是360浏览器下无法使用加入收藏夹功能。

我简单的看了下,在ie浏览器下,加入收藏夹的功能是正常的,而360显然用的是ie内核,理论上没理由不行的。

不过还是下载了360自己试了一下,没想到真的不行。。

于是开始了这次的调式:

 

首先上测试代码

 1 <id="fav" href="#">addfav</a>
 2 <script type="text/javascript">
 3     var favLink = document.getElementById('fav'),
 4         title = document.title, 
 5         href = location.href;
 6     favLink.onclick = function(e) {
 7         if (window.sidebar) {
 8             window.sidebar.addPanel(title, href, "");
 9         } else if (document.all) {
10             window.external.AddFavorite(href, title);
11         } else {
12             alert("您的浏览器不支持。");
13             return false;
14         }
15         return false;
16     }
17 </script>

事实证明,360使用的ie的内核,但是也确实没有得到预想的效果。

由于在360下,即时有错也看不到错误提示,所以简单的判断就是,window.external.AddFavorite这里是不是有问题呢。

 alert(window.external) //360 undefined & ie [object]
好吧,360下没有AddFavorite方法了。。

原生的被改了,只好放弃对360的支持了。

那么判断一下,window.external是否存在,如果不存在,就给予提示。

但是脚本并没有进入对应的分支,如下:

if(!window.external) {
    alert('360?'); // unexec
}
alert(!!window.external) //ie&360 true
呃。。。再来几个判断看看:

alert(window.external == window.undefined) //ie&360 false
alert(typeof window.external == "undefined") //ie&360 false
alert(typeof window.external == "object") //ie&360 true
我应该怎么判断才好。。。

KISSY框架倒是有判断外壳的方法,但是360提供了可以伪装ie的user-agent的选项(3q大战增加的?)

如果依赖这种方法来判断的话,依然有可能会有用户狠狠的点击着收藏链接然后大骂。。。


于是想要用捕捉错误的方式来处理,

try {
    window.external.AddFavorite(href, title);
}catch(e) {
    alert('360?');
}

然后发现,居然没有捕捉到错误!!

我好奇了,window.external到底是什么。。

alert(window.external.toString);// ie & 360 undefined

好吧,没有toString方法。。

执行window.external.toString();的时候,在ie下当然就报错了,但是360下没有报错。。

ok,终于找到方法啦。

代码
<id="fav" href="#">addfav</a>
<script type="text/javascript">
    
var favLink = document.getElementById('fav'),
        title 
= document.title, 
        href 
= location.href,
        msg 
= "浏览器不支持";
    favLink.onclick 
= function(e) {
        
if (window.sidebar) {
            window.sidebar.addPanel(title, href, 
"");
        } 
else if (document.all) {
            
try {
                window.external.toString(); 
//360下不会报错。
                alert(msg);
            }
catch(e) {
                window.external.AddFavorite(href, title);
            }
        } 
else {
            alert(msg);
            
return false;
        }
        
return false;
    }
</script>

我估摸着是360在推他自己的网络收藏夹功能,在修改中使得这个原生方法失效了。

 

 ps:有测试同事去询问在360的朋友,得到的回复是,为了安全所以禁用了加入收藏夹功能,在主程序里面写死了一个白名单。

老实说,我很好奇这个白名单中有哪些站点。。。

posted @ 2010-11-23 22:53 Akecn 阅读(1691) 评论(10) 编辑

关于IE的几个bug

前段时间做项目,由于是第一次独立做这么完整的项目demo,很郁闷、很纠结、很忙乱。。。

总之是郁闷到不行,但也得到了一些做项目的经验和教训。

其他的就不说了。


 bug描述如下

 input/text外层浮动+边距导致二倍边距

 

IE绝对定位元素神秘消失

 

都是些莫名其妙的问题,解决的方案老实说也是怪怪的,没办法,非常bug用非常手段。

突然觉得有必要手机和整理一个 ie bugs list。不然遇到这些问题还真是不知所措。

 

2010年12月2日

又发现个bug。。。ie6下position:absolute定位问题

posted @ 2010-11-19 16:40 Akecn 阅读(108) 评论(0) 编辑

KISSY字符串创建节点的bug(DOM.create)

关于bug认定:之所以认为这是bug,主要参考了jQuery实现的效果。KISSY在开发中参考了其他类库的优点,jQuery自然是其中之一。

bug描述:当利用S.Node方法将字串转换为NodeList,返回的对象是DocumentFragment对象,与预期不符。

var ps = S.Node("<p></p><p></p>").appendTo(document.body);
console.log(ps[0]); // 预期是第一个p对象,而firebug中显示,返回的是DocumentFragment对象,又因为已经append过了,在DocumentFragment对象中也不存在p元素对象了,且不存在ps[1]。如果只创建一个元素是不会有这个问题的。

bug原因分析:在创建大量元素的情况下,基于性能等原因,我们会将元素先存放到超空间中,在完成所有元素的创建以后一起添加到页面中。一般我们都是用DocumentFragment对象来存放这些创建的元素对象。初步判断KISSY保持chain特性的时候错误的将fragment对象添加到this中返回了。

源码分析:由于本人是在使用S.Node方法的时候发现这个bug的。

故在node模块(build/node/node-pkg.js)中查找Node方法,代码如下:

function Node(html, props, ownerDocument) {
    /* .. some code*/

    // handle element or text node
    if (nodeTypeIs(html, 1) || nodeTypeIs(html, 3)) {
        domNode = html;
    }
    else if (S.isString(html)) {
        domNode = DOM.create(html, props, ownerDocument);
    }

    self[0] = domNode;
}

可以看到,当传入的参数是节点或者文本对象的时候,已经就完成操作了。而如果是字符串,则调用了DOM.create方法来完成操作。
我们再看看DOM.create方法。在dom-create模块(build/dom/dom-pkg.js)中,create方法:

create: function(html, props, ownerDoc) {
    if (nodeTypeIs(html, 1) || nodeTypeIs(html, 3)) return cloneNode(html);
    if (isKSNode(html)) return cloneNode(html[0]);
    if (!(html = S.trim(html))) return null;

    var ret = null, creators = DOM._creators,
        m, tag = DIV, k, nodes;

    // 简单 tag, 比如 DOM.create('')
    if ((m = RE_SIMPLE_TAG.exec(html))) {
        ret = (ownerDoc || doc).createElement(m[1]);
    }
    // 复杂情况,比如 DOM.create('<img src="sprite.png" />')
    else {
        if ((m = RE_TAG.exec(html)) && (k = m[1]) && S.isFunction(creators[(k = k.toLowerCase())])) {
            tag = k;
        }

        nodes = creators[tag](html, ownerDoc).childNodes;

        if (nodes.length === 1) {
            // return single node, breaking parentNode ref from "fragment"
            ret = nodes[0][PARENT_NODE].removeChild(nodes[0]);
        }
        else {
            // return multiple nodes as a fragment
            ret = nl2frag(nodes, ownerDoc || doc);
        }
    }

    return attachProps(ret, props);
}

最终聚焦到1530line,nl2frag方法。同时从注释也可以看到,与bug出现的情景是一致的。而nl2frag方法的代码如下:

function nl2frag(nodes, ownerDoc) {
    var ret = null, i, len;

    if (nodes && (nodes.push || nodes.item) && nodes[0]) {
        ownerDoc = ownerDoc || nodes[0].ownerDocument;
        ret = ownerDoc.createDocumentFragment();

        if (nodes.item) { // convert live list to static array
            nodes = S.makeArray(nodes);
        }

        for (i = 0,len = nodes.length; i < len; i++) {
            ret.appendChild(nodes[i]);
        }
    }
    else {
        S.log('Unable to convert ' + nodes + ' to fragment.');
    }

    return ret;
}

这里返回的ret就是DocumentFragment对象。再看create方法,在最后返回的时候经过attachProps处理。
props是传入的另一个参数,api的解释是元素的属性,命名上也说得通。让我们看看attachProps做了哪些操作:

function attachProps(elem, props) {
    if (isElementNode(elem) && S.isPlainObject(props)) {
        DOM.attr(elem, props);
    }
    return elem;
}

实际上只是把相关的属性挂载到创建的对象上。最终返回了elem,即ret,即DocumentFragment对象。

基本上就是这样的了。

另外,附加发现DOM.create方法创建单个元素的时候返回的不是数组。。。在我看来这算是不符预期,应该也是bug吧。。

附上简单的测试代码文件

posted @ 2010-09-27 21:32 Akecn 阅读(1185) 评论(0) 编辑

KISSY源码阅读——ua

ua模块,在大部分的框架/库中代表的是浏览器判断的模块。

关于浏览器判断,
基本上都是依赖对userAgent中的标识进行识别来区分浏览器的。
看到过部分框架/库采用特征嗅探来判断,个人觉得比较不靠谱。
你不能因为A浏览器借鉴了B浏览器的某个方法或者属性就把A识别成了B对吧?
而且就目的因素来说,特征嗅探是针对功能的,而ua判断是针对浏览器标识的。
如果是为了检测功能/属性是否可用而调用ua判断浏览器,逻辑上也不合理吧。
这之间还是有差别的,可以取语意来理解。

所以个人认为,如果你需要依靠浏览器判断来使用浏览器的特征方法,那么是你显然还不了解高级js编程的基本概念;如果你使用特征嗅探来判断浏览器类别,那么你显然使用错方法了。

BTW:个人觉得ua判断的技术含量更多的是体现在代码之外的。

 

然后还是要说说KISSY的ua模块。

我们知道IE8+浏览器有兼容模式,所以有些判断不一定显得准确。在kissy源码中有点解释:

/* UA.ie && UA.ie < 8 并不意味着浏览器就不是 IE8, 有可能是 IE8 的兼容模式。进一步的判断需要使用 documentMode. */ 

另外在ua-extra模块中,增加了对国产浏览器外壳的判断。不过由于各种原因,显然版本判断很不完善。加上毕竟都不是什么独立的全新的内核,可能会觉得没必要、无所谓。
但考虑到国产浏览器会在其上增加一些所谓用户会喜欢的东西来找开发者的麻烦。所以这种尝试还是蛮有必要的。
具体的事件,可以在http://www.panghufei.com/上搜“向搜狗浏览器项目组学习”这篇文章。

文件下载:kissy-ua.js

posted @ 2010-09-25 10:49 Akecn 阅读(293) 评论(5) 编辑

KiSSY源码阅读——loader

要是不知道思路,有些奇怪的细节总是搞不明白。
在这种情况下,写源码注释感觉很不踏实。

从来没用过yui或者其他库的loader方法。
在不了解实现思路的情况下看代码,很辛苦。。

1、add一个模块,实际上只是把对应的数据保存在KISSY.Env中。并没有对KISSY做什么实质上的操作。
这个时候,模块的保存状态是undefined的。
2、当需要引用对应的模块功能的时候,需要use该模块。
     这个时候分两步操作:
     1、加载资源。
          这里不仅仅是加载模块的资源,更是要保证模块request的资源同样要加载进来。
          在开始请求资源之前设置模块的保存状态为 loading,然后发起请求。
          资源下载完成后,在回调中设置保存状态为loaded。
          只有在确认资源下载完成并且没有执行过的情况下,才会附加模块——即执行模块的主体函数。
     2、执行use的回调函数。
          调用use定义的函数,完成我们需要的操作。而我们需要的kissy实例作为唯一的参数传入该函数中。
3、全局共用一个KISSY实例。当use一个模块以后,再需要的时候就可以直接使用了。

文件下载:kissy-loader.js

posted @ 2010-09-25 10:00 Akecn 阅读(399) 评论(0) 编辑

给KISSY源码写注释——lang

摘要: 这是第二部分,关于KISSY中的lang模块。相比kissy中主要作为组织代码的方法和函数。这个模块更多的是工具类型的。文件下载:kissy-lang.js阅读全文
posted @ 2010-09-19 11:29 Akecn 阅读(275) 评论(0) 编辑

给KISSY源码写注释——kissy

摘要: 有这么一个情况,大部分时候框架的API常常让人犹豫和不知所措。除了jQuery,其他的类库大都是API看起来比源码要复杂,让人头疼。kissy在一定程度上借鉴了jQuery的接口写法,但API Docs目前看起来更偏向YUI的风格(事实上,大部分类库的风格都类似,真正的差别还是在API设计上)。所以准备要好好看看kissy的源码,并在此做个记录。还是老毛病,嘴笨——同样的,...阅读全文
posted @ 2010-09-19 10:59 Akecn 阅读(1850) 评论(0) 编辑

【无题】2010-08-17

摘要: http://yiminghe.javaeye.com/blog/734867这些提到的一些东西,其实我们很多时候是看到过的。比如:在第一次执行count方法以后,count方法已经被替换为这才是它本来就要执行的东西,其他的都是虚的。没有多余的变量,没有烦人的if-else嵌套。。我觉得yiminghe的方法很好。我喜欢这种帮你把代码理清的函数工具。提升效率有很多方面,对于web页面(特别是首页)...阅读全文
posted @ 2010-08-17 11:23 Akecn 阅读(58) 评论(2) 编辑

初学VIM的一些参考

摘要: 学习使用VIM是不少人想做的事,但是VIM的命令太多了,当然VIM的fans不一定这么想,他们会说跟本不用记,每天都用的,没必要记,用着用着就熟了。  但是对一个刚刚转而使用VIM的人来说,这话真没意义。。。  我也是初学者,正在走向使用VIM的道路。已经开始使用gVIM来编码开发了。  如果你对VIM有兴趣,而又总没办法习惯VIM而放弃。那我给出几个参考的建议。  首先,你应该对VIM很有兴趣,...阅读全文
posted @ 2010-07-23 20:03 Akecn 阅读(138) 评论(0) 编辑
仅列出标题  下一页

公告