push pull poll 长连接 websocket pushlet cometd

IBM总结文章:

http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

 

里面推荐的pushlet之前使用过的,这次再看一下,看源码和试验ajax push实质仍然是pull技术。?

它的脚本库没有考虑到其他脚本库,使用window.onEvent来作为回调,不是很好。

示例不是很好,只写了pull方式的。

不建议用,看到用的人没多少,网上的帖子都是粘来粘去,没有实际的例子,日期很早,最近的没有。

看他的文档也写的不清楚,看了一天没看明白,还是不知道怎么用。确定不是自己理解力问题。

 

webqq通过观察应该是长轮询,再看到这边篇帖子的大讨论:

http://www.iteye.com/topic/785931?page=7

主要以下几点:

认为是长轮询实现

认为长轮询较好:

长轮询的优势是,如果没有消息,客户端N秒才会有一次请求。
如果有消息,也会立即发送到客户端。(如果刚好回应完一个请求时有新消息... 还是有一定延时)
与iframe + script方式的长连接相比,它实现更简单,也不会在浏览器下显示“正在加载”信息。

按个人理解,使用带部分缓冲的长轮询能减少服务器开锁
即有新消息并不立即返回,而是等待一定时间,以免消息频繁时过多轮询。[这又存在延迟的问题]

长连接存在进度条一直加载的问题。

 

服务端要配合使用nio(tomcat6.jetty支持)较好,否则压力较大。

别的实现有使用cometD的。

 

之前自己做过长连接,主要问题是浏览器一直在转,让人很不舒服,而且容易崩溃。

flash主要是防火墙的问题。

 

长轮询比较好实现,注意客户端要延长超时时间。

一般的长poll是不需要comet就可以实现的,只不过Tomcat6之后支持Bayeux协议可以使用nio/异步servlet来提高性能。

Ext.Ajax.request({
                    url : 'LongPoll',
                    timeout:360000,//延长超时
                    success : function(response, opts) {
                        console.log('finish');
                        dorq();
                    },
                    failure : function(response, opts) {
                        console.log('server-side failure with status code '
                                + response.status);
                    }
                });

 

这里有一些列很好的文章:

反向Ajax:

第1部分:Comet介绍 http://kb.cnblogs.com/page/112185/

Forever Iframe

Forever Iframe(永存的Iframe)技术涉及了一个置于页面中的隐藏Iframe标签,该标签的src属性指向返回服务器端事件的servlet路径。每次在事件到达时,servlet写入并刷新一个新的script标签,该标签内部带有JavaScript代码,iframe的内容被附加上这一script标签,标签中的内容就会得到执行。

1. 优点:实现简单,在所有支持iframe的浏览器上都可用。

2. 缺点: 没有方法可用来实现可靠的错误处理或是跟踪连接的状态,因为所有的连接和数据都是由浏览器通过HTML标签来处理的,因此你没有办法知道连接何时在哪一端已被断开了。

Multi-part XMLHttpRequest

1. 优点:只打开了一个持久连接,这就是节省了大部分带宽使用率的Comet技术。

2. 缺点:并非所有的浏览器都支持multi-part标志。某些被广泛使用的库,比如说用Java实现的CometD,被报告在缓冲方面有问题。例如,一些数据块(多个部分)可能被缓冲,然后只有在连接完成或是缓冲区已满时才被发送,而这有可能会带来比预期要高的延迟。

流方式,服务端要知道客户端是否关闭也是个问题,否则客户端已经断开,服务端仍在运行,可能的解决办法是心跳,那不跟poll差不多了。

第2部分: WebSocket http://kb.cnblogs.com/page/112616/

第3部分:Web服务器和Socket.IO http://kb.cnblogs.com/page/114594/

第4部分:Atmosphere和CometD http://kb.cnblogs.com/page/116653/

Atmosphere和CometD都是稳定的、开源的反向Ajax解决方案,我们在Ovea选用的是CometD,因为我们在一个集群环境内部为移动设备开发可伸缩的事件驱动应用,我们完全掌控基础设施(我们使用Jetty)。不过,在没有额外开发的情况下,如果你正在出售web应用且希望你的反向Ajax功能在尽可能多的服务器上都可运作的话,CometD可能不是最好的选择。但现在随着越来越多的Web应用开始支持Servlet 3.0规范,CometD的局限性呈下降趋势。说到传输层,余下的主要差异则取决于对WebSocket的支持。

关于servlet 3.0 参见 http://blog.ureshika.com/archives/635.html ,在此文中主要指异步servlet处理。Ovea是php网站,但是使用java的CometD来做comet服务?

作者还是倾向于cometD,但是cometD要求jetty6以上以及任何支持Servlet 3.0规范的服务器中

第5部分:事件驱动的Web开发 http://kb.cnblogs.com/page/117099/

comet有多种实现,long poll,长连接,上面的文章仍然推荐long poll。

cometD可以使用websocket作为传输协议。

WebSockets与Bayeux/CometD http://www.infoq.com/cn/news/2010/05/websockets-bayeux

文中提到的Greg Wilkins是jetty作者

http://www.htmlgoodies.com/html5/tutorials/making-html5-websockets-work.html#fbid=x32iZkQSYda

此文中写道支持websocket的浏览器有:

IEFirefoxChromeSafariOpera
10~6.014.05.0 (partial support*)11.0 (partial support*)

支持webscoket的服务容器有

Java的Jetty(原文竟然写作Betty)  Oracle的Glassfish

php 的Wamp and XAMPP, lighttpd的mod_websocket

python的Tornado

nodejs + http://socket.io/  (socket.io是javascript库,包括服务端和客户端,所以要在nodejs上跑了)

微软的那就不说了

 

再来总结一下:

Well,本来是想找到关于websocket的有利消息,但是让我失望了。原因是:

1:目前主流的php服务器支持不行:apache,ngix不支持, java中的tomcat7,jboss7,webshpere8都还没支持。

2:浏览器支持也不给力:目前只FF6,Chrome14支持,况且websocket还只是个html5草案。

3:假使花个大力气做出来了,然后你发现其实long poll也能同样做的更好,不知你会怎么想。

再来看看CometD这个东西:

引用http://kb.cnblogs.com/page/116653/ 中的话:

1. 优点

从客户端到服务器端,以及从一个独立的Java客户端到服务器端,CometD提供了一个完整的解决方案。框架有详尽的文档说明,有一个很好的API,且非常容易使用。最重要的是,它拥有一种事件驱动的方法。CometD和Bayeux是许多事件驱动应用的构成部分,其他的反向Ajax框架并未提供任何的事件驱动机制,使得最终用户不得不开发自己的定制解决方案。

javascript有dojo和jquery的支持。

CometD支持许多必需的功能,比如说重连接、可靠的超时检测、回退、批处理、消息确认,以及更多你不会在其他反向Ajax框架中找得到的功能。CometD可让你实现最可靠的、低延时的通信。

2. 缺点
除了Jetty for Comet(Tomcat)之外,CometD目前并未支持任何的Servlet 2.5容器,其也不支持Glassfish/Grizzly WebSocket。

我的观点:

java实现,所以,关php什么事?关那么多的php 应用什么事?这不过是java众多框架中的又一个。

不支持Servlet 2.5容器,我自己实现long poll还不是一样?啊,对,它在上面封装了一层,不过这个转换服务器的情况真的很可能发生吗?即使会,转换的工作会很难吗?它的封装对性能有影响吗?

我难道有点势力吗,用了java鄙视.net,用了php轻视java?

Continue reading push pull poll 长连接 websocket pushlet cometd

将目录或指定文件使用img2py进行处理

img2py 可以将图片文件存成文本文件,但它不支持多个文件处理,这特别在我的目录下有许多的文件,如果一个个处理的话,会非常麻烦。于是为了解决目录及支持多个文件的问题,我编写了下面的小程序,希望对你有用。

import wx.tools.img2py as img2py
import getopt
import sys
import os
import os.path

def usage():
    print """
%s [-d directory][-h] -o outputfile files
""" % sys.argv[0]

def main():
    if len(sys.argv) == 1:
        usage()
        sys.exit(1)
    try:
        opts, fileArgs = getopt.getopt(sys.argv[1:], "d:o:h")
    except getopt.GetoptError:
        usage()
        sys.exit(1)

    imagedir = ''
    outputfile = ''
    for opt, val in opts:
        if opt == "-h":
            usage()
            sys.exit(1)
        elif opt == "-d":
            imagedir = val
        elif opt == "-o":
            outputfile = val

    convert(outputfile, imagedir, fileArgs)

def isImageFile(filename):
    f, ext = os.path.splitext(filename)
    if os.path.isfile(filename) and ext.lower() in ('.gif', '.png', '.bmp', '.jpg', '.ico'):
        return True
    else:
        return False
           
def convert(outputfile, dir='', imagefiles=[]):
    files = []
    files.extend(imagefiles)
    if dir:
        f = [os.path.join(dir, x) for x in os.listdir(dir) if os.path.isfile(os.path.join(dir, x))]
        files.extend(f)
    files = list(set([x for x in files if isImageFile(x)]))
    for i, x in enumerate(files):
        name = os.path.splitext(os.path.basename(x))[0].lower()
        cmd =[]
        if i != 0:
            cmd.append('-a')
        cmd.append('-n')
        cmd.append(name.capitalize())
        cmd.append(x)
        cmd.append(outputfile)
        os.system("img2py %s" % " ".join(cmd))
   
if __name__ == '__main__':
    main()

我们在写gui程序的时候,经常会用到一些图标图片资 源,对此有几种解决办法,有人喜欢用zip模块将其打包,用的时候取出来,因为python读取zip文件也是很方便的,有人则干脆不打包,直接放在一个 子目录中,用的时候直接读取。而我则喜欢将其转换为.py文件,作为模块调用。

我在看wxPython程序的例程的时候,[encode_bitmaps.py]发现它的图片是从一个模块(.py文件)中调入的,于是很好奇,顺藤摸瓜,于是发现:

wxPython安装好之后,会在 wx\tools 目录下安装一些工具,其中名为img2py.py的工具。
这个工具可以很方便的将我们程序中所用到的图片或者图标资源转换成py文件,这样我们在需要使用这些图片资源的时候,只需要
import 这些扩展名为.py的模块文件即可

在命令行下输入img2py.py并回车,可以查看详细的帮助信息。而一般情况下,我们所要做的,只是将图片转换为.py文件

例如,我有一个ico文件,想用其作为我程序的托盘图标

那么我可以这样做

首先,将其转换为 .py 文件

img2py.py myicon.ico myicon.py 

 

然后,在程序中导入这个模块

import myicon 

最后,当我需要用它的时候,只需要:

icon = myicon.geticonIcon() 

注意,如果你的myicon.py中没有geticonIcon()方法,只需要加入如下一行语句即可:

geticonIcon = icon.GetIcon 

怎么样,是不是很方便?

在 wx\tools 目录下还有一些其他的工具,具体用法还有待大家发掘

--------------------------------------------------

目的:
        即为img2py的用处,img2py是将图像转为以py文件存储的程序,简化了程序过程中读文件的处理。

开发环境:eclipse+pydev插件

步骤:
1,在 eclipse工程中增加个含有main函数的模块,用来处理图片到py,代码如下:
'''
Created on 2009-6-16
@author: fengxuanshuo

This is a way to save the startup time when running img2py on lots of
files...

'''
import sys
from wx.tools import img2py

command_lines = [
                 "-a -F -n book   pictures/right_menu/222.png   ../main/images.py",
                 "-a -F -n boo   pictures/right_menu/111.png   ../main/images.py",
                 "-a -F -n ook_red   pictures/right_menu/000.png   ../main/images.py",
                 ]

if __name__ == '__main__':
    for line in command_lines:
        args = line.split()
        img2py.main(args)

其中command_lines为命令行执行内容,程序需要的图片都可以处理,而且目标文件可以有多个,名字自己取。

2,执行新增加的模块,就会发现 main目录多了个images.py文件。

3,更新eclipse pydev工程:pydev插件并没有常用的那个add file to project选项,不过有pydev->source format python files.

4,然后再原工程里面就可以用图片py文件了(可能有些版本,在生成py文件的时候不会加import相关库的语句,需要手动添加)

5,images.py 在wxpython demo 中的用法
定义全局变量 images: images =None
在app里面声明全局的images : globel images
import imgaes as i
images = i

其他py文件类似,这么做的好处在demo的注释里面说了,不罗嗦了,over

Continue reading 将目录或指定文件使用img2py进行处理

jsp 缓存, html 缓存, ajax缓存,解决方法

 

有关页面缓存问题.这个问题上网找了 好多.但发觉各种解决方法,都彼此分离,没有一篇统一的解决方法,本人近日,也遇到了页面缓存的问题,根据网上各页面缓存的解答,做了一个总结。

1.服务器端缓存的问题, 防止JSP页面缓存:

  1. <% 
  2. // 将过期日期设置为一个过去时间 
  3. response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT"); 
  4. // 设置 HTTP/1.1 no-cache 头 
  5. response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate"); 
  6. // 设置 IE 扩展 HTTP/1.1 no- cache headers, 用户自己添加 
  7. response.addHeader("Cache-Control", "post-check=0, pre-check=0"); 
  8. // 设置标准 HTTP/1.0 no-cache header. 
  9. response.setHeader("Pragma", "no-cache"); 
  10. %> 

<% // 将过期日期设置为一个过去时间 response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT"); // 设置 HTTP/1.1 no-cache 头 response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate"); // 设置 IE 扩展 HTTP/1.1 no-cache headers, 用户自己添加 response.addHeader("Cache-Control", "post-check=0, pre-check=0"); // 设置标准 HTTP/1.0 no-cache header. response.setHeader("Pragma", "no-cache"); %>

当然,每一个页面都包含这些代码会很繁琐,可以通过自定义过滤器 (Filter)的方法来处理相关的页面

2.防止html页面缓存

  1. <meta http-equiv="pragma" content="no-cache"> 
  2. <meta http-equiv="cache-control" content="no-cache"> 
  3. <meta http-equiv="expires" content="0">    

<meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0">

3.防止Ajax缓存

如果,你的页面,已经设置了防止JSP,HTML的页面缓存,但发觉页面缓存, 始终存在,就要考虑是否Ajax造成的页面缓存了。

1)设置了,如上1,2之后

Ajax缓存,产生的原因是:request, url的地址上:
IE中如果XMLHttpRequest提交的URL与历史一样则使用缓存,根本不向服务器端提交。因此无法取到刚提交的数据。

针对ajax,需要如下设置:

方法一:加时间戳 var url = BaseURL + "&timeStamp=" + new Date().getTime();
方法二:加随机数 var url = BaseURL + "&r=" + Math.random();

总结:原引(http://www.javaeye.com/topic/150162)

在jsp页面中,光是使用html的<meta> tag是无法禁止缓存的。一定要加上

response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);

有人肯定会说,这个跟html的tag设置没有不同啊。的确,我也觉得,但实践证明,没有这几句,光靠html tag不行。

所以当action会返回页面时,有以下这两种情况:

a,返回的页面没有写上上面的禁止cache的语句(或者只写了html tag)。IE存储的是URL link + page result(cache eabled)。这也就是导致了之前为什么还会有cache的原因

b,返回的页面写上了禁止cache语句 。IE存储的是URL link + page result(cache disabled)。这样才能够实现到我们想要的目的。每次都会真正的发出request。

Continue reading jsp 缓存, html 缓存, ajax缓存,解决方法

编码与控制台

public void testReadPackageResourceToString()
{

try
{

String s1 = FileUtils.readPackageResourceToString("co/common/util/iso8859.html",null,"iso-8859-1");

String s2 = FileUtils.readPackageResourceToString("co/common/util/utf8.html",null,"utf-8");
String s3 = FileUtils.readPackageResourceToString("co/common/util/gbk.html",null,"gbk");
// you should change the console's encoding to utf-8
// System.out.println(new String(s1.getBytes("utf-8")));
// System.out.println(new String(s2.getBytes("utf-8")));
// System.out.println(new String(s3.getBytes("utf-8")));
//
byte[] cs = s2.getBytes();//错的
byte[] cs1 = new String(s2.getBytes("utf-8")).getBytes();//对的
byte[] cs2 = new String(s2.getBytes("utf-8"),"utf-8").getBytes();//错的
byte[] cs3 = s2.getBytes("utf-8");//对的
byte[] cs4 = new String(s2.getBytes("utf-8"),"cp1252").getBytes(); //对的,与二相同
System.out.println("====s2.getBytes()=======");
for (int i = 0 ; i < cs.length ; i++)
{
System.out.println(cs[i]);
}
System.out.println("====new String(s2.getBytes(\"utf-8\"),\"utf-8\").getBytes();=======");
for (int i = 0 ; i < cs1.length ; i++)
{
System.out.println(cs1[i]);
}
System.out.println("====new String(s2.getBytes(\"utf-8\"),\"utf-8\").getBytes()=======");
for (int i = 0 ; i < cs2.length ; i++)
{
System.out.println(cs2[i]);
}
System.out.println("====s2.getBytes(\"utf-8\");=======");
for (int i = 0 ; i < cs3.length ; i++)
{
System.out.println(cs3[i]);
}
System.out.println("====new String(s2.getBytes(\"utf-8\"),\"cp1252\").getBytes()=======");
for (int i = 0 ; i < cs4.length ; i++)
{
System.out.println(cs4[i]);
}
// System.out.println(s2);
// System.out.println(new String(s2.getBytes("utf-8"),"utf-8"));
// System.out.println(new String(s2.getBytes()));
// System.out.println(new String(s2.getBytes(),"utf-8"));
}
catch (IOException e)
{
e.printStackTrace();
fail();
}

}

String.getBytes(encoding) 是将字符串编码到指定格式

new String

                    Charset 和 Encoding 的区别是什么?

在绝大多数情况下,包括某些专业文章中,字符集和编码都统称为编码,这是因为一个字符集往往对应一种编码。但是在程序中,我们来不得半点马虎,我们 应该清楚地知道字符集和编码有什么区别。以 ASP.NET 为例,Response.Charset 和 Response.Output.Encoding(只读)中的 Charset 和 Encoding 有什么区别呢?

Charset 是字符集,Encoding 是编码。

  • 字符集即字符的集合,规定了在这些集合里面有哪些字符,每一个字符都有一个编号(一个整数),但这只是编号 不是编码。
  • 编码就规定了一个编号如何与二进制交互。

我们大多数人最先接触到的字符集是 1963 年的 ASCII,其中的每一个字符只需要用一个字节来表示就可以了。但世界上有许多种语言,像亚洲文字,比如中文,常用汉字就几千个,仅用一个字节来表示显然 是不够的,假如我们使用两个字节。

那么问题就来了,为什么我们要把两个字节看成是一个汉字的编号呢?为什么我们不把两个字节看成 ASCII 字符集的两个编号呢?为了解决此问题,就得使用编码来标识了。

还有一个问题,编号(整数)1234 在字符集 A 中代表“千”,1234 在字符集 B 中代表“一”,那么 1234 究竟代表什么字呢?这就得明确字符集了。

浏览器可以自动识别使用哪个字符集,一般说来它们使用 HTTP 头部的 Content-Type 标明的字符集,如果没有向 HTTP 头部发送该信息,一般参考使用 HTML 的 head 标签中的 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />,为什么是参考使用呢?因为现在浏览器都比较聪明,如果发现这里用错了,一般会给予纠正。

我们做网页时,如果指定的 Charset 是 GB2312,那么就不应该在网页中出现繁体字,因为 GB2312 标准只有几千个简体的中文字。如果我们的网页编码是 UTF-8,我们就不要指定字符集是 GB2312,因为虽然 UTF-8 编码对应的 UTF-8 字符集包含了 GB2312 的字符,但同一个字符在两个字符集中的编号不一样。

对于我们中文简体网页,一般来说有两种搭配:

  • 一种是字符集是 GB2312,编码使用 ANSI。占用磁盘空间最少,网络传输效率最高。
  • 一种是字符集是 UTF-8,编码使用 UTF-8。虽然占用磁盘空间大,传输效率略低,但因为兼容面广,在应用 Ajax 以及包含多种语言文字时使用方便。鉴于此原因,现在许多网页开发工具都默认使用 UTF-8 来保存网页,比如 Visual Web Developer
在web中
response.setContentType("text/javascript; charset=utf-8");
response.setCharacterEncoding("utf-8");
Writer out = response.getWriter();//要注意这一句不要放在设置编码的语句之前,否则不起作用。

Continue reading 编码与控制台

javascript call和apply最基本的作用

<html>
<head>
<script language="javascript"> 

function Animal(){ 
   this.name = "a"; 
   this.showName = function(){ 
       alert(this.name); 
   } 
function Cat(){
this.name = "c";
Animal.call(this);
Cat.prototype = new Animal();
var cat = new Cat(); 
cat.showName();    //但是alert的是a而不是c,还不是完全的对象继承
alert(cat instanceof Animal);   //True

 
</script>
</head>
<body></body>
</html>

<html>
<head>
<script language="javascript"> 

function Animal(){ 
   this.name = "a"; 
   this.showName = function(){ 
       alert(this.name); 
   } 
function Cat(){
Animal.call(this);//这一句应该在开头,因为这个操作会执行将Animal的属性赋值给Cat的操作,它会覆盖这一句之前的属性
this.name = "c";
Cat.prototype = new Animal();
var cat = new Cat(); 
cat.showName();//alert的是c
alert(cat instanceof Animal);//True

 
</script>
</head>
<body></body>
</html>

apply and call
    它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式有所区别:
     apply(thisArg,argArray);
     call(thisArg[,arg1,arg2…] ]);

知道这些也就差不多了
========================================================================

详解 http://www.javaeye.com/topic/155109

领悟 JavaScript 中的面向对象

 

注:读完本文后请务必接着看完所有回复!

JavaScript 是面向对象的。但是不少人对这一点理解得并不全面。

在 JavaScript 中,对象分为两种。一种可以称为“普通对象”,就是我们所普遍理解的那些:数字、日期、用户自定义的对象(如:{})等等。

还有一种,称 为“方法对象”,就是我们通常定义的 function。你可能觉得奇怪:方法就是方法,怎么成了对象了?但是在 JavaScript 中,方法的确是被当成对象来处理的。下面是一个简单的例子:

Js代码
  1. function func() {alert('Hello!');} 
  2. alert(func.toString()); 

function func() {alert('Hello!');} alert(func.toString());
在这个例子中,func 虽然是作为一个方法定义的,但它自身却包含一个 toString 方法,说明 func 在这里是被当成一个对象来处理的。更准确的说,func 是一个“方法对象”。下面是例子的继续:

Js代码
  1. func.name = “I am func.”; 
  2. alert(func.name); 

func.name = “I am func.”; alert(func.name);
我们可以任意的为 func 设置属性,这更加证明了 func 就是一个对象。那么方法对象和普通对象的区别在哪里呢?首先方法对象当然是可以执行的,在它后面加上一对括号,就是执行这个方法对象了。

Js代码
  1. func(); 

func();
所以,方法对象具有二重性。一方面它可以被执行,另一方面它完全可以被当成一个普通对象来使用。这意味着什么呢?这意味着方法对象是可以完全独 立于其他对象存在的。这一点我们可以同 Java 比较一下。在 Java 中,方法必须在某一个类中定义,而不能单独存在。而 JavaScript 中就不需要。

方法对象独立于其他方法,就意味着它能够被任意的引用和传递。下面是一个例子:

Js代码
  1. function invoke(f) { 
  2.     f(); 
  3. invoke(func); 

function invoke(f) { f(); } invoke(func);
将一个方法对象 func 传递给另一个方法对象 invoke,让后者在适当的时候执行 func。这就是所谓的“回调”了。另外,方法对象的这种特殊性,也使得 this 关键字不容易把握。这方面相关文章不少,这里不赘述了。

除 了可以被执行以外,方法对象还有一个特殊的功用,就是它可以通过 new 关键字来创建普通对象。

话说每一个方法对象被创建时,都会自动 的拥有一个叫 prototype 的属性。这个属性并无什么特别之处,它和其他的属性一样可以访问,可以赋值。不过当我们用 new 关键字来创建一个对象的时候,prototype 就起作用了:它的值(也是一个对象)所包含的所有属性,都会被复制到新创建的那个对象上去。下面是一个例子:

Js代码
  1. func.prototype.name=”prototype of func”; 
  2. var f = new func(); 
  3. alert(f.name); 

func.prototype.name=”prototype of func”; var f = new func(); alert(f.name);
执行的过程中会弹出两个对话框,后一个对话框表示 f 这个新建的对象从 func.prototype 那里拷贝了 name 属性。而前一个对话框则表示 func 被作为方法执行了一遍。你可能会问了,为什么这个时候要还把 func 执行一遍呢?其实这个时候执行 func,就是起“构造函数”的作用。为了形象的说明,我们重新来一遍:

Js代码
  1. function func() { 
  2.     this.name=”name has been changed.” 
  3. func.prototype.name=”prototype of func”; 
  4. var f = new func(); 
  5. alert(f.name); 

function func() { this.name=”name has been changed.” } func.prototype.name=”prototype of func”; var f = new func(); alert(f.name);
你就会发现 f 的 name 属性不再是"prototype of func",而是被替换成了"name has been changed"。这就是 func 这个对象方法所起到的“构造函数”的作用。所以,在 JavaScript 中,用 new 关键字创建对象是执行了下面三个步骤的:

  1. 创建一个新的普通对象;
  2. 将方 法对象的 prototype 属性的所有属性复制到新的普通对象中去。
  3. 以新的普通对象作为上下文来执行方法对象。

对 于“new func()”这样的语句,可以描述为“从 func 创建一个新对象”。总之,prototype 这个属性的唯一特殊之处,就是在创建新对象的时候了。

那么我们就可以利用这一点。比如有两个方法对象 A 和 B,既然从 A 创建的新对象包含了所有 A.prototype 的属性,那么我将它赋给 B.prototype,那么从 B 创建的新对象不也有同样的属性了?写成代码就是这样:

 

Js代码
  1. A.prototype.hello = function(){alert('Hello!');} 
  2. B.prototype = new A(); 
  3. new B().hello(); 

A.prototype.hello = function(){alert('Hello!');} B.prototype = new A(); new B().hello();
这就是 JavaScript 的所谓“继承”了,其实质就是属性的拷贝,这里利用了 prototype 来实现。如果不用 prototype,那就用循环了,效果是一样的。所谓“多重继承”,自然就是到处拷贝了。

JavaScript 中面向对象的原理,就是上面这些了。自始至终我都没提到“类”的概念,因为 JavaScript 本来就没有“类”这个东西。面向对象可以没有类吗?当然可以。先有类,然后再有对象,这本来就不合理,因为类本来是从对象中归纳出来的,先有对象再有类, 这才合理。像下面这样的:

Js代码
  1. var o = {}; // 我 发现了一个东西。 
  2. o.eat = function(){return "I am eating."// 我发现它会吃; 
  3. o.sleep = function(){return "ZZZzzz..."// 我 发现它会睡; 
  4. o.talk = function(){return "Hi!"} // 我发现它 会说话; 
  5. o.think = function(){return "Hmmm..."} // 我 发现它还会思考。 
  6.  
  7. var Human = new Function(); // 我决定给它起名叫“人”。 
  8. Human.prototype = o; // 这个东西就代表了所有“人”的概念。 
  9.  
  10. var h = new Human(); // 当我发现其他同它一样的东西, 
  11. alert(h.talk()) // 我就知道它也是“人”了! 

var o = {}; // 我发现了一个东西。 o.eat = function(){return "I am eating."} // 我发现它会吃; o.sleep = function(){return "ZZZzzz..."} // 我发现它会睡; o.talk = function(){return "Hi!"} // 我发现它会说话; o.think = function(){return "Hmmm..."} // 我发现它还会思考。 var Human = new Function(); // 我决定给它起名叫“人”。 Human.prototype = o; // 这个东西就代表了所有“人”的概念。 var h = new Human(); // 当我发现其他同它一样的东西, alert(h.talk()) // 我就知道它也是“人”了!

 

=================================================================================

/**
作者认为第三种理解较正确,见最后
**/
prototype属性,只有function对象中才具有的显式属性;

网上三种理解:
            1:通过构造函数创建的普通对象,通过其constructor属性引用它的构造函数对象,从而间接引用(拥有)了构造对象中的prototype对象;

如图:

此观点的文章:   参看 jimichan的文章:详解 javascript类继承机制的原理 中的: “(说成间接的是因为每个object 都有一个 constructor 属性指向它的构造函数)。”
非常感谢在此问题上,作者对我的回信;如有冒犯,敬请原谅;

            2:构造函数创建对象时,copy prototype中的属性和代码给所创建的对象。从而使创建的对象拥有了prototype中的所有功能和属性;

如图:

此观点的文章:   参看 yiding_he的文章:领悟 JavaScript 中的面向对象 中的:  “ 在 JavaScript 中,用 new 关键字创建对象是执行了下面三个步骤的:

   1. 创建一个新的普通对象;
   2. 将方法对象的 prototype 属性的所有属性复制到新的普通对象中去。
   3. 以新的普通对象作为上下文来执行方法对象。”

此观点在回贴中被 xieye反对

            3:构造函数在创建对象时,把构造函数中的prototype引用赋给创建的普通对象;也就是说由构造函数创建的对象,都有一个指针指向 prototype对象;

如图:

此观点的文章:   参看 李站的文章:悟透javascript中的" 我们已经知道,用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:第一步是建立一个新对象;第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象;第 三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作。对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象 有关,与构造函数再扯不上关系了"   以及  “语法甘露 中的:上面代码的最后一句证明,新创建的对象的constructor属性返回的是Object函数。其实新建的对象自己及其原型里没有 constructor属性,那返回的只是最顶层原型对象的构造函数,即Object。”

综上所述:根据贴子:领悟 JavaScript 中的面向对象 中作者 afcn0的回贴 “其实还有补充,就是如果构造函数返回object类型,那new对象无效,prototype问题是楼主还不 太了解prototype继承方式,__proto__属性,以及isPrototypeOf方法所至 ” 的提示,查阅了文章:javascript 中的继承

Html 代码
  1. 此文中提 到:jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau"); 
  2.  
  3. 调用这句时,都发生了什么: 
  4.  
  5. 1 当js看见 new操作符,它创建一个新的普通对象,并且设置它的__proto__ 属性为Engineer.prototype。 
  6.  
  7. 2 new 操作符传递这个新的对象作为Engineer 构造器的this的值。 
  8.  
  9. 其实最主要做的事就是上面的两件,剩下的都是很简单的函数调用. 

根据上文的提示作了简单测试:

Javascript 代码
  1. function person(name,b){ 
  2.     this.name=name; 
  3.  
  4. person.prototype.sayHello=function(a){ 
  5.     //alert("hello,i am "+this.name); 
  6.     alert(this==a); 
  7.     } 
  8.  
  9.  
  10. function employee(name, salary) 
  11.     person.call(this, name);    //调用上层构造函数 
  12.     this.salary = salary;       //扩展的成员 
  13. }; 
  14.  
  15. var p=new person("yangsp",p); 
  16. //p.sayHello(p); 
  17. //alert(p.constructor); 
  18.  
  19. //下面两句验证了普通对象中确有_proto_属性,且引用的是prototype对象;(在ff下调试,ie下不 可); 
  20. alert(p.__proto__==person); 
  21. alert(p.__proto__==person.prototype)) 
  22.  
  23. //alert("p有prototype属性吗? "+p.prototype);    //表明普通对象中没有 prototype属性;                              

总结:

Html 代码
  1. 比较赞同 第三种理解; 
  2.       即:prototype是function对象中专有的属 性。 
  3.           _proto_是普通对象的隐式属性,在new的时候,会指向 prototype所指的对象; 
  4.           普通对象中的constructor属性指向构造 函数,因此一个用构造函数创建的对象可能有两种方式关联到prototype.但继承应该是根据_proto_关联到prototype属性; 

另外:ecma-262中提到:every object created by that constructor has an implicit reference to the prototype (called the object's prototype) associated with its constructor 以及其图示;不敢肯定它的implicit reference间接还是隐式链接;

Continue reading javascript call和apply最基本的作用

样式表hack-区别IE和非IE浏览器

只看第一个就差不多了:


1.区别IE和非IE浏览器

#tip {
background:blue; /*非IE 背景藍色*/
background:red \9; /*IE6、IE7、IE8背景紅色*/
}


2.区别IE6,IE7,IE8,FF

【区别符号】:「\9」、「*」、「_」
【示例】:
#tip {
background:blue; /*Firefox 背景变蓝色*/
background:red \9; /*IE8 背景变红色*/
*background:black; /*IE7 背景变黑色*/
_background:orange; /*IE6 背景变橘色*/
}

【说明】:因为IE系列浏览器可读「\9」,而IE6和IE7可读「*」(米字号),另外IE6可辨识「_」(底线),因此可以依照顺序写下来,就会让浏 览器正确的读取到自己看得懂得CSS语法,所以就可以有效区分IE各版本和非IE浏览器(像是Firefox、Opera、Google Chrome、Safari等)。


3.区别IE6、IE7、Firefox (方法 1)

【区别符号】:「*」、「_」
【示例】:
#tip {
background:blue; /*Firefox背景变蓝色*/
*background:black; /*IE7 背景变黑色*/
_background:orange; /*IE6 背景变橘色*/
}

【说明】:IE7和IE6可读「*」(米字号),IE6又可以读「_」(底线),但是IE7却无法读取「_」,至于Firefox(非IE浏览器)则完全 无法辨识「*」和「_」,因此就可以透过这样的差异性来区分IE6、IE7、Firefox


4.区别IE6、IE7、Firefox (方法 2)

【区别符号】:「*」、「!important」
【示例】:
#tip {
background:blue; /*Firefox 背景变蓝色*/
*background:green !important; /*IE7 背景变绿色*/
*background:orange; /*IE6 背景变橘色*/
}

【说明】:IE7可以辨识「*」和「!important」,但是IE6只可以辨识「*」,却无法辨识「!important」,至于Firefox可以 读取「!important」但不能辨识「*」因此可以透过这样的差异来有效区隔IE6、IE7、Firefox。


5.区别IE7、Firefox

【区别符号】:「*」、「!important」
【示例】:
#tip {
background:blue; /*Firefox 背景变蓝色*/
*background:green !important; /*IE7 背景变绿色*/
}

【说明】:因为Firefox可以辨识「!important」但却无法辨识「*」,而IE7则可以同时看懂「*」、「!important」,因此可以 两个辨识符号来区隔IE7和Firefox。


6.区别IE6、IE7 (方法 1)

【区别符号】:「*」、「_」
【示例】:
#tip {
*background:black; /*IE7 背景变黑色*/
_background:orange; /*IE6 背景变橘色*/
}

【说明】:IE7和IE6都可以辨识「*」(米字号),但IE6可以辨识「_」(底线),IE7却无法辨识,透过IE7无法读取「_」的特性就能轻鬆区隔 IE6和IE7之间的差异。


7.区别IE6、IE7 (方法 2)

【区别符号】:「!important」
【示例】:
#tip {
background:black !important; /*IE7 背景变黑色*/
background:orange; /*IE6 背景变橘色*/
}

【说明】:因为IE7可读取「!important;」但IE6却不行,而CSS的读取步骤是从上到下,因此IE6读取时因无法辨识 「!important」而直接跳到下一行读取CSS,所以背景色会呈现橘色。


8.区别IE6、Firefox

【区别符号】:「_」
【示例】:
#tip {
background:black; /*Firefox 背景变黑色*/
_background:orange; /*IE6 背景变橘色*/
}

【说明】:因为IE6可以辨识「_」(底线),但是Firefox却不行,因此可以透过这样的差异来区隔Firefox和IE6,有效达成CSS hack。

Continue reading 样式表hack-区别IE和非IE浏览器

【转】什么是Cookie

当微软还没有推出IE8的时候,老实说,我就不喜欢这个浏览器。这不是来自于我对微软的偏见(这个公司确实非常伟大),而是来自于我对Cookie这个美好事 物的无比忠诚。但是,IE8的出现,让我们的美好蒙上一层厚厚的阴影。不过,当一切还没有变得非常严重之前,让我们先来了解一下Cookie是什么,它对 于我们的意义,以及我们为什么需要捍卫它。

  • 什么是Cookie以及Cookie的作用

Cookie是在你浏览网页的时候,网站服务器放在客户端(Client End,就是你的电脑)里面的一个小小的TXT文件。这个文件里面存储了一些与你访问的这个网站有关的一些东西,当你下一次访问这个网站的时 候,Cookie就会记住你上次访问时候的一些状态或者设置,让服务器针对性的发送页面的相关内容。Cookie里面包含的信息并没有一个标准的格式,各 个网站服务器的规范都可能不同,但一般会包括:所访问网站的域名(domain name),访问开始的时间,访问者的IP地址等客户端信息,访问者关于这个网站的一些设置等等。比如,你设置的诸如Google一个页面要显示几条搜索 结果之类的信息,即使你不登录你的Google账号,你下次访问时也能够保存下来,这就是上次你访问时把相关信息放入了Cookie的效果。如果是在线购 物网站,还记录了一些你的购物车,储物架以及你的账户名等信息。另外有些网站则会通过Cookie把你的登录账号和密码记下来,这样你下次打开浏览器就会 自动登录。

当然,如果你在系统文件夹中打开Cookie的TXT文件,你并不会看到这些信息而只能看到一串乱七八糟的字符,因为为了安全起 见,Cookie的内容一般都是加密的,只有对应的服务器才能读懂。另外,由于Cookie只是TXT文件,而不是程序,更不是病毒,不能自己运行,不会 对操作系统和其他任何计算机程序产生影响,也不会通过互联网传播,因此它对互联网安全实际上不构成威胁。

对于网站分析而言,Cookie的作用在于帮助嵌入代码类的网站分析工具记录网站的访问(Visit)和访 问者(Unique Visitor)的信息,没有Cookie就无法实现相关监测。而通过服务器端Log来进行网站分析的软件则不需要Cookie也能实现相关分析,因此 Cookie只对嵌入代码类工具有效。那些你耳熟能详的工具——Google Analytics、Omniture、HBX、WebTrends(嵌入代码版)等等,都需要在网站访问者的电脑上放置Cookie才能实现监测。

  • Cookie的数量和时效

Cookie的数量是指一个网站可以在客户端放置Cookie的个数。一个网站并不是只能放置一个Cookie在客户端,而是根据需要,会放置 多个不同的Cookie。对网站分析工具而言,帮助监测Visit的Cookie和帮助监测Unique Visitor的Cookie就不能是一个,而应该分开设置。对每一个网站(域)而言,不同浏览器能够支持的最多Cookie数是不同 的。IE7和FireFox3.0支持每个网站50个Cookie,而Opera则支持30个。无论是30还是50,基本都够用了。

Cookie的时效(expiration)是另一个非常重要的概念,也是Cookie的重要属性之一。任何Cookie都是有时效的,有些 Cookie的有效时间很短,有些Cookie则在浏览器关闭的同时自动失效,而有些则是号称”永久Cookie”。其实,Cookie的时效是在服务器 端人为设置的,可以设置为1秒,也可以设置10年,也可以设置在浏览器关闭的同时失效,完全根据不同情况的需要。永久Cookie就是指那些时效很长的 Cookie,但不是真的永久。

Cookie的时效性对于网站分析监测意义重大。Visit的监测依赖于Cookie的时效。例如,Google Analytics对Visit的Cookie设置了两个时效,一个是30分钟,另一个是浏览器关闭时。这就意味着,如果Visit Cookie在30分钟内没有更新,这个Cookie就失效了——这就是为什么我们说Visit这个度量衡量的是间隔不超过30分钟的页面浏览过程,如果 两次页面浏览之间的时间超过了30分钟,那么Visit计数会被增加1。另外,如果你打开一个网站,看了一会儿就关掉浏览器,那么当你再次打开浏览器重新 开这个网站的时候,即使两次浏览没有超过30分钟,也会被计算为一个新的Visit,原因就是Visit Cookie浏览器关闭时效结束的设置起的作用。

Unique Visitor也依赖于Cookie的时效。如果这个Cookie的时间设定为2天失效,那么你今明两天都访问同一个网站,Unique Visitor只会记录为从0增加到1;而如果你第三天又来,那么Unique Visitor就会再增加计数一次,共计2次。除了Visit和Unique Visitor外,Return visitor、Frequency等等度量当然也依赖于Cookie的时效。

  • 1st party cookie和3rd party cookie

  第一方Cookie和第三方Cookie其实是一个 非常简单的概念,但是我在百度上随便搜索了一些解释,好像都不是很清楚,也不是很准确。实际上,所谓第一方和第三方的说法,是用来确定Cookie的归属 的,这个归属是指Cookie中记录的域(domain)。举个例子:如果你访问我的这个网站www.chinawebanalytics.cn的时候, 我的网站在你的电脑上设置了一个Cookie,里面的记录的域名也是www.chinawebanalytics.cn,那么这个Cookie就是第一方 的,归你访问的网站www.chinawebanalytics.cn所有。而如果你访问网站www.chinawebanalytics.cn时,在你 的计算机中设置的Cookie的域名是www.omd.com,那么这个Cookie就是第三方Cookie,归www.omd.com所有。

对于网站分析而言,这个概念是非常重要的。例如,你会问Google Analytics使用的Cookie是1st party的,还是3rd party的。答案是第一方的。首先,Google Analytics在每个被监测网站上的Cookie都是由我们熟悉的监测javascript代码所创建的(是的,javascript也可以创建 Cookie,知道这点就够了,不需要深挖),其次,这个被创建的cookie的域不是analytics.google.com,而是被监测网站自己的 域。因此,虽然这个Cookie实际上是在Google Analytics的帮助下建立的,而且也为Google Analytics所用(反而不能被“被监测网站”直接利用),它仍然是第一方Cookie。

所以,第一方Cookie并不一定需要由某个网站自己的服务器给自己建立,别的网站也能为它建立;而且,第一方Cookie也不一定是能由某个 网站自己读取的,它完全可能由第三方读取。第一方和第三方的唯一区别只是:Cookie中的域名是否和被访问网站的域一样,是就是第一 方,否就是第三方。

这真的是一个容易混淆的概念,希望看了我上面的内容您弄清楚了。

网站分析和所有的互联网广告的监测,都会更喜欢第三方Cookie。原因是,第三方Cookie可以用来监 测跨网站的访问者行为。例如,DoubleClick使用的就是第三方Cookie,这个公司会为你打开的所有载有DoubleClick广告的页面建立 同一个(仅一个)域为DoubleClick的Cookie,这样,只要你打开了这些网页,无论它们是否属于同一网站,你的浏览广告的行为 DoubleClick都能知道。但是第一方Cookie就不行了,因为第一方Cookie得用被监测网站的域,这样多个网站就会有多个不同的 Cookie,跨网站浏览行为就无法监测了。

对于大多数浏览器而言,第三方Cookie是被默认关闭的,原因在于人们在讨论 Cookie涉及的隐私问题时,倾向于认为第三方Cookie极 大的获取了人们的行为隐私,并由此产生了对第三方Cookie普遍的不信任和误解。但事实上,所有的Cookie都不会泄露任何关于浏览者个人的隐私信 息,它捕捉的仅仅只是浏览行为本身,第三方Cookie也不例外。而如果所有人都愿意接受第三方cookie,那么网站分析能够给出的分析和优化方案会更 多。但可惜,因为第三方Cookie被普遍禁用,因此利用第三方Cookie的监测工具并不多,只有监测网络广告的工具才会坚持使用第三方Cookie。

  • 没有Cookie,还能监测到什么?

由于第三方Cookie不受欢迎,很少有网站分析工具会采用它。而如果完全没有Cookie,那么网站分析工具几乎无法工作。但实际上,如果没 有Cookie,还是能监测到一点儿东西的。这个东西是PV。因为PV的监测只要引发javascript监测代码就可以,跟cookie无关。例如,在 Omniture中,如果某个客户端禁用cookie,Omniture还是会记录这个客户端贡献的PV,但完全无法记录Visit,这就会使这个工具监 测的PV/Visit会比实际值略大。说点儿题外话:在没有Cookie的时候,Omniture会退而求其次用访问者客户端IP地址来辨别不同的 Visitor(Unique Visitor),这样禁用cookie后unique visitor其实还能监测,但由于visit不能监测了,因此有可能在Omniture中出现Unique Visitor大于Visit的情况。

没了Cookie,除了PV,其他的度量基本上就获得不了数据了,所以我会认为没有Cookie,我们什么都没了。或 者Visitor和Visitor所在的地理位置还能通过IP地址获得,但众所周知的原因,这个数据是非常不精确的,我们需要Cookie。

那么,你会问,多少客户端会禁用Cookie呢?我没有精确的数字,但我认为第一方Cookie应该会有大概80%的用户正在使用,只有20% 左右会禁用它。而第三方Cookie,由于是默认不开启的,因此我估计顶多只有20%的人在使用它。

随着IE8的出现,肯定会进一步降低Cookie的使用率,这也将进一步降低网站分析数据的样本数量。我不认为这 会降低网站分析工具在描述定性问题时的准确性(定性问题例如Bounce Rate,例如Time on site,以及Returning visitor和New visitor的比例),但在描述定量问题时会出现误差,或者更确切地说会偏小。如果随着Cookie禁用比例的增加,超过50%的人都禁用的话,那么网 站分析的原有方法论就会有麻烦了。不过,我肯定不相信Cookie禁用比例会有剧烈的上升,我很乐观——Cookie带给人们的方便远远要比一些不足一提 的隐私问题要多的多要大的多。禁用Cookie更多只是心理的慰藉(其实大多数时候一定只是心理上的感觉,而没有什么实际的对安全和隐私的帮助),但带来 的不方便则会直接影响你的浏览体验。

因此,无论是为了我们的专业本身,还是为了让浏览网页的用户有更好的体验,或是为了让网站本身能够创造更多的便利化应用,我们都有足够的理由支 持Cookie,反对微软的IE8色情浏览模式,捍卫我们应该捍卫的——这代表着智慧和进步。Eric Peterson写给总统奥巴马的那封公开信值得看看,这代表着我们所有网站分析从业者的最强烈呼声。

Continue reading 【转】什么是Cookie

javascript 打印

javascript 打印
使用iframe,写入类容,window.print打印,这个很简便。[测试sfari,firefox,ie,chrome都支持,opera不支持]
<html>
    <head>
        <style >
body {
    background-color: blue;
    background-color: red \9;
}
</style>
    <script type="text/javascript">
        function pt(){
            var ifa=document.getElementById('ifa');
            var doc=ifa.contentWindow.document;
            doc.write('ssssss');
            doc.close();
            ifa.contentWindow.print();
        }
    </script>        
    </head>
    <body>blabla
    <a onclick="pt();" href="#">print</a>
    <iframe id="ifa" ></iframe>
    </body>
</html>
但是要注意iframe的内容应该本页同域,否则有权限限制。

ie有问题,iframe打印不是iframe那个页面的内容而是iframe所在页面的内容。
解决办法,针对ie使用document.execCommand('print');即可

Continue reading javascript 打印

Pagination


Total views.

© 2013 - 2024. All rights reserved.

Powered by Hydejack v6.6.1