张慧的博客

张慧的博客

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  45 Posts :: 0 Stories :: 24 Comments :: 0 Trackbacks

置顶随笔 #

对于Servlet的生命周期,主要围绕着init()、service()和destroy()三个回调方法展开的。什么是回调方法?通俗的说就是这三个方法定义完后由web容器负责在特定时间(需要的时候)调用。

Servlet容器,如Tomcat一般会在用户第一次请求Servlet的时候实例化该对象。另一种情况是在服务器启动时立即加载并实例化,但这需要在web.xml文件中对Servlet进行load-on-startup的配置。

当第一个用户请求到来时,服务器根据部署描述符找到所访问的Servlet类,并查找当前容器,发现没有此类的实例,说明是第一次访问此Servlet,所以容器开始加载Servlet,并实例化此对象,实例化之后会立即调用init()方法,而且init()方法由始至终只被调用一次,所以比较适合进行对象的初始化工作,比如读取配置文件,初始化属性等。当调用完init()方法后,Servlet实例处于ready状态,这时开始调用其service()方法,并等待着下一次请求的到来。

service()方法是服务方法,只要再有请求到来,服务器都会产生一个新的线程,调用service()方法,进行相关的服务。service()方法会检查HTTP请求的类型(GET、POST等),来相应的调用doGet()、doPost()等。GET请求起因于正常URL请求,或没有指定Method的HTML表单;Post请求起因于将Method定为Post的HTML表单。从图中可见,service()方法可以被调用多次,因为之后用户每一次访问该Servlet,都会触发服务器调用service()方法。

如果实例长时间未被访问,或者web服务器关闭,则容器会负责调用destroy()方法,该方法可以将一些资源释放,destroy()方法也是只被调用一次,之后Servlet实例将被JVM回收空间。这样通过init()-->service()-->destroy(),完成了Servlet的一个生命周期。

上图是UML中的状态图,形象的描述了一个对象在不同事件触发时,其内部状态的变更过程。实心的圆圈代表初始状态,代表Servlet刚刚被实例化:中间写Ready的椭圆形代表就绪状态,最下面的圆圈代表结束,这时对象已被JVM的GC回收。图中的另外一个分支,代表在执行init()操作时抛出了异常,造成无法调用service()方法,生命周期提前终止。

posted @ 2012-07-08 23:33 张慧 阅读(1222) | 评论 (0)编辑 收藏

这是在一个opensource项目中看到的获取访问者ip的方法: 
/**
      * 获取访问者IP
      * 
      * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
      * 
      * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
      * 如果还不存在则调用Request .getRemoteAddr()。
      * 
      * 
@param request
      * 
@return
      
*/
     public static String getIpAddr(HttpServletRequest request) {
         String ip = request.getHeader("X-Real-IP");
         if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
             return ip;
         }
         ip = request.getHeader("X-Forwarded-For");
         if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
             // 多次反向代理后会有多个IP值,第一个为真实IP。
             int index = ip.indexOf(',');
             if (index != -1) {
                 return ip.substring(0, index);
             } else {
                 return ip;
             }
         } else {
             return request.getRemoteAddr();
         }
     }
posted @ 2012-07-08 23:31 张慧 阅读(2251) | 评论 (0)编辑 收藏

在java中经常需要获取一些系统信息,如系统的资源空间等。下面就是一些Runtime的应用:


public static void main(String[] a){
         Runtime runtime 
= Runtime.getRuntime();
         
long freeMemoery = runtime.freeMemory();
         
long totalMemory = runtime.totalMemory();
         
long usedMemory = totalMemory - freeMemoery;
         
long maxMemory = runtime.maxMemory();
         
long useableMemory = maxMemory - totalMemory + freeMemoery;
         
         System.out.println(
"当前时间:"+runtime);
         System.out.println(
"系统闲置空间:"+freeMemoery);
         System.out.println(
"系统总空间:"+totalMemory);
         System.out.println(
"系统被用的空间:"+usedMemory);
         System.out.println(
"系统最大空间:"+maxMemory);
         System.out.println(
"系统可用空间:"+useableMemory);
     }

运行效果:


当前时间:java.lang.Runtime@c3c749
 系统闲置空间:
4873672
 系统总空间:
5177344
 系统被用的空间:
303672
 系统最大空间:
66650112
 系统可用空间:
66346440

 

posted @ 2012-07-08 23:30 张慧 阅读(695) | 评论 (0)编辑 收藏

2012年8月16日 #

CSS(Cascading Style Sheet) 层叠样式表,一种和Html联系非常大的标记语言,主要用户控制网页的样式,并能把样式和网页内容分离,因此能大大提高网页开发的效率。

       初识CSS,感觉这个名字有点难以理解,“样式表”理解起来比较容易,就是定义网页的样式,也可以叫风格,那层叠怎么理解呢?

       这要从CSS的继承说起,学过面向对象的话,对继承一定不陌生,CSS的继承更简单一些:

   

在Html中各个标签可以看作是一个个容器,例如:

  1. <span style="font-size:18px;"><p>详解CSS的<em>名称</em>含义</p></span>  

       这一句话中,<p>标签是一个大容器,里面有<em>标签 ,我们把<p>标签定义成父标签,那么<em>标签就成了子标签。当我对<p>标签(父标签)用CSS样式时,字标签会完全继承父标签的风格,当然这种关系可能会有更多层(上面的例子为两层):

这张图上,每个子标签都会继承父标签的样式,这种层层嵌套的关系,也就是CSS名称的含义。

posted @ 2012-08-16 22:29 张慧 阅读(1541) | 评论 (0)编辑 收藏

经常用到多个透明图片层叠,但又需要获取不同图片的点击事件,本文实现图片透明区域穿透点击事件。

效果图:

 欢迎转载请说明转自:http://blog.csdn.net/aminfo/article/details/7872748

一、先上图片,这2张图片尺寸是一样的,放到drawable目录下:

图1:transparent.png

 

图2:transparent2.png

 

二、上布局文件,test.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width
="fill_parent"
   android:layout_height
="fill_parent"
   android:orientation
="vertical"
   android:gravity
="center"
   android:id
="@+id/mainLayout">
   
    <ImageView android:id="@+id/ImageView01"
        android:layout_width
="wrap_content"
        android:layout_height
="wrap_content"
        android:src
="@drawable/transparent"/>
    
    <ImageView android:id="@+id/ImageView02"
        android:layout_width
="wrap_content"
        android:layout_height
="wrap_content"
        android:src
="@drawable/transparent2"/>    
          
</FrameLayout>

package org.shuxiang.test;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class MainActivity extends Activity
{
    private ImageView iv1;
    private ImageView iv2;
    private Bitmap bitmap1, bitmap2;
    private boolean iv1Transparent = false;
    private boolean iv2Transparent = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.test);

        iv1 = (ImageView) findViewById(R.id.ImageView01);
        iv2 = (ImageView) findViewById(R.id.ImageView02);
        bitmap1 = ((BitmapDrawable) (iv1.getDrawable())).getBitmap();
        bitmap2 = ((BitmapDrawable) (iv2.getDrawable())).getBitmap();
        
        iv1.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if(iv1Transparent)
                {
                    Log.i("test", "图1透明区域");
                }
                else
                {
                    Log.i("test", "图1点击");                    
                }
            }
            
        });
        
        iv1.setOnTouchListener(new OnTouchListener()
        {
            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) 
            {
                // TODO Auto-generated method stub
                if(bitmap1.getPixel((int)(arg1.getX()),((int)arg1.getY()))==0)
                {
                    Log.i("test", "图1透明区域");
                    iv1Transparent = true;    //透明区域设置true                    
                }
                else
                {
                    Log.i("test", "图1实体区域");
                    iv1Transparent = false;
                }
                return false;
            }            
        });
        
        iv2.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if(iv2Transparent)
                {
                    Log.i("test", "图2透明区域");
                }
                else
                {
                    Log.i("test", "图2点击");                    
                }
            }
            
        });
        
        iv2.setOnTouchListener(new OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                if(bitmap2.getPixel((int)(event.getX()),((int)event.getY()))==0)
                {
                    Log.i("test", "图2透明区域");
                    iv2Transparent = true;    //透明区域设置true
                    iv1.dispatchTouchEvent(event);
                }
                else
                {
                    Log.i("test", "图2实体区域");
                    iv2Transparent = false;
                }
                return false;
            }
        });
    }
}


posted @ 2012-08-16 22:28 张慧 阅读(2912) | 评论 (0)编辑 收藏


需求大致分为三种:
1.震动
2.系统音效(无需提供音频文件)
3.自定义音效(需提供音频文件)
我的工具类的封装:

  1. //  
  2. //  WQPlaySound.h  
  3. //  WQSound  
  4. //  
  5. //  Created by 念茜 on 12-7-20.  
  6. //  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.  
  7. //  
  8.   
  9. #import <UIKit/UIKit.h>  
  10. #import <AudioToolbox/AudioToolbox.h>  
  11.   
  12. @interface WQPlaySound : NSObject  
  13. {  
  14.     SystemSoundID soundID;  
  15. }  
  16.   
  17. /** 
  18.  *  @brief  为播放震动效果初始化 
  19.  * 
  20.  *  @return self 
  21.  */  
  22. -(id)initForPlayingVibrate;  
  23.   
  24. /** 
  25.  *  @brief  为播放系统音效初始化(无需提供音频文件) 
  26.  * 
  27.  *  @param resourceName 系统音效名称 
  28.  *  @param type 系统音效类型 
  29.  * 
  30.  *  @return self 
  31.  */  
  32. -(id)initForPlayingSystemSoundEffectWith:(NSString *)resourceName ofType:(NSString *)type;  
  33.   
  34. /** 
  35.  *  @brief  为播放特定的音频文件初始化(需提供音频文件) 
  36.  * 
  37.  *  @param filename 音频文件名(加在工程中) 
  38.  * 
  39.  *  @return self 
  40.  */  
  41. -(id)initForPlayingSoundEffectWith:(NSString *)filename;  
  42.   
  43. /** 
  44.  *  @brief  播放音效 
  45.  */  
  46. -(void)play;  
  47.   
  48. @end  


  1. //  
  2. //  WQPlaySound.m  
  3. //  WQSound  
  4. //  
  5. //  Created by 念茜 on 12-7-20.  
  6. //  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.  
  7. //  
  8.   
  9. #import "WQPlaySound.h"  
  10.   
  11. @implementation WQPlaySound  
  12.   
  13. -(id)initForPlayingVibrate  
  14. {  
  15.     self = [super init];  
  16.     if (self) {  
  17.         soundID = kSystemSoundID_Vibrate;  
  18.     }  
  19.     return self;      
  20. }  
  21.   
  22. -(id)initForPlayingSystemSoundEffectWith:(NSString *)resourceName ofType:(NSString *)type  
  23. {  
  24.     self = [super init];  
  25.     if (self) {  
  26.         NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] pathForResource:resourceName ofType:type];  
  27.         if (path) {  
  28.             SystemSoundID theSoundID;  
  29.             OSStatus error =  AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &theSoundID);  
  30.             if (error == kAudioServicesNoError) {  
  31.                 soundID = theSoundID;  
  32.             }else {  
  33.                 NSLog(@"Failed to create sound ");  
  34.             }  
  35.         }  
  36.           
  37.     }  
  38.     return self;  
  39. }  
  40.   
  41. -(id)initForPlayingSoundEffectWith:(NSString *)filename  
  42. {  
  43.     self = [super init];  
  44.     if (self) {  
  45.         NSURL *fileURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];  
  46.         if (fileURL != nil)  
  47.         {  
  48.             SystemSoundID theSoundID;  
  49.             OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &theSoundID);  
  50.             if (error == kAudioServicesNoError){  
  51.                 soundID = theSoundID;  
  52.             }else {  
  53.                 NSLog(@"Failed to create sound ");  
  54.             }  
  55.         }  
  56.     }  
  57.     return self;  
  58. }  
  59.   
  60. -(void)play  
  61. {  
  62.     AudioServicesPlaySystemSound(soundID);  
  63. }  
  64.   
  65. -(void)dealloc  
  66. {   
  67.     AudioServicesDisposeSystemSoundID(soundID);  
  68. }  
  69. @end  


调用方法步骤:
1.加入AudioToolbox.framework到工程中
2.调用WQPlaySound工具类

2.1震动

  1. WQPlaySound *sound = [[WQPlaySound alloc]initForPlayingVibrate];  
  2. [sound play];  

2.2系统音效,以Tock为例

  1. WQPlaySound *sound = [[WQPlaySound alloc]initForPlayingSystemSoundEffectWith:@"Tock" ofType:@"aiff"];  
  2. [sound play];  

2.3自定义音效,将tap.aif音频文件加入到工程

  1. WQPlaySound *sound = [[WQPlaySound alloc]initForPlayingSoundEffectWith:@"tap.aif"];  
  2. [sound play];  

tap.aif音频文件样例下载点击

posted @ 2012-08-16 22:26 张慧 阅读(7488) | 评论 (0)编辑 收藏

2012年8月8日 #

 状态图主要描述一个对象在其生命周期内的状态变化,对象由事件驱动并满足一定的条件从一个状态转换到另一个状态。状态图显示了一个状态机。


下面是一个表示借书的状态图(描述书的状态转换)



状态图都由哪些元素组成呢?

一、初始状态


      初始状态是状态机的起始位置,它不需要事件的触发。一个状态图只能有一个初始状态。状态图总是以初始状态开始,以终止状态结束

二、状态


状态是对象执行某项活动或等待某个事件时的条件。状态可以由以下几部分组成:

1、Name:状态名称
2、Entry/Exit Action:进入和退出动作
3、Internal Transition:内部转移(对事件作出响应,执行一定的动作,但不会发生状态的转换)
4、Do:状态保持不变时执行的动作
5、SubStage:子状态(当状态是复合状态时)
6、Deferred Event:延迟事件(未在本状态中处理,但不被丢弃,而是延迟到其它状态中处理的事件)


下面是一个灯的点燃状态的例子


       如果一个状态比较复杂,那么它还可以拥有子状态,拿上面借书的例子,书的被借状态又可包含两个子状态:被正常借、被续借


三、转移

      上面已经讲过了一种特殊的转移:内部转移,但是这种转移只是响应一定的事件,执行一定的动作,并不会放生状态的转移
下面介绍一下一般转移的格式:


状态的转移一般由三部分组成

1、event(事件):触发状态转移的原因
2、Guard Condition(保卫条件):是一个布尔表达式,当事件被触发时要判断保卫条件的值,值为True才会发生状态的转换
3、Action(活动):状态转换时执行的活动

下面是一个电水壶烧水的状态转换


       当事件turn on放生时,只有水壶内有水(have water)才能由off状态转换到on状态,并发生烧水的动作(Boiling Water)。其实动作也可以放在on状态中。

四、结束状态



结束状态表示状态机执行结束或对象生命的终结,一个状态图可以有多个结束状态


      在实际的应用中,不必为每个对象都创建状态图,而是只为那些比较复杂的,状态比较多的对象创建状态图。状态图是一种很有用的图,它可以帮助我们分析复杂对象的状态转换和对象在什么时候执行什么样的动作。网上购物过程中,我们会经常查看订单的状态,描述订单的状态机就是一个比较经典的状态图,网上有很多关于订单状态图的例子,大家可以查一下,我在这里就不再赘述了。
posted @ 2012-08-08 23:38 张慧 阅读(5769) | 评论 (0)编辑 收藏

1. 为什么要时间管理    曾经有过这样一个报道:有一名记者随机采访了几个人,问了这样一个问题:
    你认为你的时间是由自己来掌控的吗?得到的回答却是这样的:
    如今各种竞争如此激烈,能拉到一个客户不容易,只要客户一个电话,我就马上要出现,我的时间完全由客户掌控。
    我只不过是一名普通的小职员,主管给我安排什么我就做什么。自己掌控时间?!等我当了经理再说吧。
    我总是有忙不完的工作,哪还来得及自己安排时间?别开玩笑了。
    在这样一个信息爆炸的社会里,我不抓紧时间充电就会落后了,现在是时间在控制我啊!
    相信你对这个问题会有自己的见解,但是仔细想想你的答案是否跟他们的很类似呢?像他们一样,也有这样的困惑或是感受呢?之所以有这样的困惑,有一个最主要的因素在影响着我们,这个因素是什么呢?
    职位?竞争?时间?
    每个人的时间总是不够用,人们渴望找到一种灵丹妙药,彻底改变自己时间不够用的局面。你是否也是这里的一员呢?

2. 概述    时间是一种资源,我们无法对它进行买卖,不可能与别人分享或是从别人那里获得,也不可能得到更多或是拥有更少。
    每天,我们每一个人都拥有相同数量的时间——24小时,差别在于我们用它来做什么。之所以每个人会有种种的困惑,究其原因,是因为大多数人在时间的管理上存在着很多误区,只有消除这些误区,才有可能让我们把时间管理得更好、更有效。
    我们现在就一起去看看这些误区都是什么样的吧!

3. 误区展示    当你的工作中出现问题时,你认为是什么原因造成的?
    无论,你的实际情况是怎么样的,往往我们都忽略了一个最关键的问题,那就是“时间”。
    因为时间的不充足而没来得及做这个或是做那个,导致最后的结果总是不尽如人意。所以,每个人在时间管理上都或多或少存在一定的问题,这也是接下来我们要解决的问题。请点击下一页吧。

4. 反思    这个世界上根本不存在“没时间”这回事。
    如果你跟很多人一样,也是因为“太忙”而没时间完成自己的工作的话,那请你一定记住,在这个世界上还有很多人,他们比你更忙,结果却完成了更多的工作。这些人并没有比你拥有更多的时间,他们只是学会了如何更好地利用自己的时间而已!有效的利用时间是一种人人都可以掌握的技巧——就像开车一样。
    因此,希望大家能通过这门课程的学习,在今后的生活中有效的珍惜时间,而一旦把握好时间,你就掌握了自己的生命,并能够将其价值发挥到极限。

5. 时间管理课程概述    在本课程中,将通过四个方面的内容帮助你更好的掌握自己的时间,而不是成为时间的奴隶,从而让你实现自己的人生目标。
    首先,我们要谈谈人生目标,也就是我们花了时间都做了些什么,比如你想成为什么样的人,你将来要达到一种什么样的成就等。
    第二、当你有了明确的人生目标,那该用什么方法来实现呢,也就是接下来要讲的时间管理的核心思想“时间管理矩阵”等。
    第三、了解了如何管理时间,那么接下来要介绍的是怎么来自我管理。如何利用好每一天的时间来帮助我们实现人生的大目标。
    最后,就是学会利用工具来管理时间。
    总而言之,对于你来说,这个世界上没有任何东西比时间更加重要了。每个人的时间都是相同的,我们每个人每个星期都只有168个小时,不可能有更多的时间。
    这门课程可以帮助你更有效的利用这些时间。
    让我们开始吧!

6. 概述    时间我们无法随意的让它变大或是缩小,我们也不能像存钱一样把时间储备起来,以备不时之需;更不能用其它的东西来代替,甚至我们更不能把已经失去的时间像倒带子一样,有选择性的倒回来或是快放。
    因此,当人们无所事事,或者忙得晕头转向却不见成效时,应该暂时停下来审视一下自己的时间利用效率,审视一下自己在时间中所处的角色,寻找一条更为合适的途径,实现自己的目标,追求自己的人生价值。
    在经理人的所有管理技能中,时间管理最容易被忽略。初级经理人从员工的岗位过渡到管理者的岗位,比较容易忽略管理的角色和时间管理的技能,而中、高级管理者的工作时间更忙碌,工作任务更多,时间效率的管理也就显得更加重要。

7. 案例    假设一个人的生命中有三枚硬币,第一枚代表财富,第二枚代表健康,第三枚代表时间,请问哪一个更重要?
    无论你选择了什么,我们来逐一分析一下吧。

8. 分析一    这三枚硬币哪个更重要呢?
    第一种情况:
    通常人们都趋向于追求财富,如果在这三枚硬币中,把代表财富的硬币拿掉,则表示这个人有足够多的健康,也有足够多的时间,他有可能重新去创业,赢得财富,把代表财富的硬币重新放进自己的生命中。
    你赞成这个说法吗?
    赞成    不赞成
    无论你选择了什么,我们来看一个实例:
    房地产大亨李嘉诚,相信你一定听说过吧!
    17岁独自外出闯荡,经商60多年,建立起亚洲最大的商业王国。 
    李嘉诚现在年过八旬仍然精神矍铄,思维敏捷。他说:“健康就好似堤坝一样,如果快要崩堤了再做补救,花费多少人力物力可能救不回来。”
    问到成功秘诀时,李嘉诚认为惜时如金,是他的一个成功秘诀,李嘉诚每天清晨不到6点就起床了,中午不睡午觉,晚上睡觉前还要看书。
    李嘉诚认为:在商业竞争中,你输了,那么你输在时间;反之,你赢了,也赢在时间。

9. 分析二    第二种情况:
    如果在这三枚硬币中,把代表健康的硬币拿掉,这表示这个人有足够多的财富,也有足够多的时间,则他可以花费无以计数的金钱来治疗自己的疾病,至少可以拖延一定的时间,或借助高科技手段来延长生命,他可能把代表健康的硬币重新放进自己的生命中。
    你赞成这个说法吗?
    赞成    不赞成
    我想梅艳芳大家都听说过吧?
    梅艳芳患癌后,每周必须接受5天的治疗,光是每个月的医药费就高达港币80万,一年下来要花近千万港币。她可以用财富延长自己的生命,并用这些有限的生命完成自己最后的心愿,但是健康依然离她很遥远。

10. 分析三    第三种情况:
    如果把代表时间的硬币拿走,让一个人没有自己的时间了,这时候,即使他有无数的财富,有很强壮的身体,可是生命留给他的只有一刹那,他无法用1亿美元去换10分钟,这就好比无数的0前面没有了1,是没有任何意义的,他不仅不能将代表时间的硬币重新放进自己的人生,而且财富和健康对他也变得毫无意义了。
    你赞成这个说法吗?
    赞成    不赞成
    无论你选择的是什么,时间对我们确实很重要。
    大家都知道,秦始皇是第一位统一六国并实现了文化及货币统一的皇帝。
    他为了让自己永远稳坐江山,就派人去寻找长生不老药。他非常清楚时间就是生命,如果自己能永生就等于掌握了时间并永远稳坐江山。
    最终,还是以失败告终。即便他有再多的财富与健康的体魄,他依然无法实现永生的愿望。因为时间不会根据任何人的愿望而改变。

11. 总结    总之,对于所有的人,尤其是经理人、企业家,他们有大量的金钱,可是他们感到最缺的还是时间,所以对时间的要求就更高,这就需要良好的时间管理。时间管理就是有效地应用时间这种资源以便我们有效地取得个人的重要目标。
    接下来,就让我们一起来学习有关个人目标的内容吧。

12. 自我时间状态判断    学习了时间管理的重要性和概念,现在我们一起应用这些知识来分析一下你自己吧!

13. 拖延商数测试    在回答这些问题时,一方面是为了让你重新认识一下自己,另一方面这些可能也是你浪费时间的原因。
    现在请做一个测试,看看你做事的拖延情况究竟如何吧。
    你的拖延情况严重吗?
    做事拖延,会严重浪费你的时间,一起来看看浪费时间的因素具体是哪些吧。时间盗贼:(找东西、懒惰,时断时续,一个人包打天下,偶发延误,惋惜不已/做白日梦,拖拖拉拉,对问题缺乏理解就匆忙行动,消极情绪,分不清轻重缓急)

14. 小结    至此,我们已经了解了时间管理的误区有哪些,以及时间管理的定义、必要性,同时通过测试对自己有了新的认识。
    如果你确认对上述内容已经完全掌握,就请开始下一章的学习吧!

15. 概述  你有人生目标吗?请你试着回答下面的问题:
  你现在是把时间真正用在你想做的事情上了吗?
  你是在“原地踏步”吗?
  你正在左右为难——是前进还是放慢脚步,或者正在犹豫不决?
  如果你不能把时间用来去实现你认为最重要的目标的话,那么你就要对其进行调整。现在请点击下一页让我来帮助你一起回答以上这些问题吧。

16. 为什么需要目标    为什么要设定人生目标呢?
    许多人拼命埋头苦干,却不知所为何来,到头来却发现追求的梯子搭错了墙,懊悔不已,只可惜为时已晚,之所以有的人总是很忙碌,而做的事情却没有太大意义,就是因为他们没有一个明确的目标。
    你现在处于最理想的状态吗?
    最理想的状态是指,你所做的每件事对你都是有价值的——其价值在于它积极推动你实现职业上的或是个人生活上的目标——这些事情都是你希望可以完成的。没有其他人可以替你做决定,你必须得明确什么事情对于你来说才是最重要的。
    需要注意的是,实现目标,需要一个过程。而在过程中的每一个阶段,都会有一个阶段性目标,越往后发展,阶段性目标就越接近最终目标。正是通过每一个阶段性目标的成功实现,才能实现最终目标。因此,目标永远指明了前进的方向。
    现在你明白为什么需要目标了吗?
    请继续学习后面的内容吧。

17. 人生目标序言    大人们总喜欢问自己的孩子:你长大了想做什么啊?
    小孩子会毫不犹豫的说:
    “我要像爸爸一样,当一名建筑工程师……”
    “我要当一名科学家或是一名作家……”
    “我要像妈妈一样,当一名医生……”
    “我要当一名警察或者天文学家……”
    “我要当一名宇航员,飞上太空……”
     …… …… ……
    各种各样的回答,都代表了孩子的一个人生目标。
    你认为这些目标可以更改吗?
    无论你的目标是否发生变化,时间都会一分一秒的过去,这是一个不变的规律。

18. 要明确人生目标    为了加深你对目标的理解,一起来看看这样一组调查数据。
    表中列出了某一年哈佛大学400名学生及他们毕业后25年的调查数据。那些没有目标的人,结果是生活在社会的底层,而那些目标明确的人,都生活在社会的中上层。令人深思的是,这些人的起点几乎是一样的,然而,正是因为目标这一因素导致了巨大的结果差异。可见,目标对人生的影响是多么的巨大。
    到这里,我想问你一个问题,你有长期或者短期的目标吗?
    有没有不重要,希望从这一刻开始,你要为自己设定明确且合理的长期与短期目标。
    现在,请写出你的人生目标:
    请拿出几张纸,一支铅笔或钢笔,一只带有秒针的手表或时钟,为自己设定15分钟时间。在纸的最上端写下问题。

19. 你的人生目标到底是什么?    第一个问题:
    你的人生目标到底是什么?
    用第一人称、现在时、肯定语气来写,这样,这些目标就能立即进入你的潜意识中。
    不要害怕写出那些看起来距离自己很遥远的目标。这些目标可以是有形的或是无形的。
    比如说登上珠穆朗玛峰、去参加马拉松长跑、休假一年、退休后在意大利建一座房子、买艘游艇、购买一辆宝马轿车;拥有一个美满幸福的三口之家,自己能拥有一个健康的身体……这些都可以列出来,同时请列出优先顺序。

20. 如何度过今后三年    第二个问题:
    如何度过今后三年?
    三年的时间,看似很长,那么在这么长的时间里你能做些什么呢?
    你可以写下一些比较空泛的目标,比如说“获得幸福”、“取得成功”、“赢得爱情”、“为社会做贡献”、“读完30本书”、“游遍30个国家”等等。

21. 只能活六个月你该怎样渡过    第三个问题:
    只能活六个月怎样度过?
    如果你知道自己会在六个月后因为病魔的侵入而失去生命,你会怎样度过这六个月的时间?你可以从不同的角度去想。
    请注意:这意味着你的人生只剩下六个月的时间,你必须充分利用这段时间做一些你觉得最重要或者自己一直都想做而没做的事情。

22. 三个问题之间的思考    你可以花上至少两分钟的时间,仔细斟酌并修改你对以上三个问题的回答。如果愿意,你也可以花上更多的时间。
    同时,请你认真思考一下这三个问题之间的关系是怎样的?
    现在我们来分析一下这三个问题:第一个可以看作是长期目标、第二个是短期目标、第三个是被分解后的目标。
    你可能会发现第二个问题的答案其实是第一个问题答案的延伸,还有一些人发现自己在第三个问题上的答案跟前两个问题的答案截然不同——那是因为他们突然意识到自己的时间不多了,必须在有限的时间内完成最重要、最紧急的事情。

23. 如何设定人生目标    了解为什么设定人生目标后,现在我们就来学习一下如何设定人生目标吧。
    事实上,设定一个适当的目标就等于达到了目标的一部分。
    人生的大目标也是人生大志,可能需要十年、二十年甚至终生为之奋斗。一个人不可能一口吃成一个胖子,所以我们在追求人生目标的过程中,要时刻清楚自己现在做的每一件事都要有助于实现自己最终的目标。
    接下来,我们就详细讲解一下如何有效地设定人生目标。

posted @ 2012-08-08 23:38 张慧 阅读(1456) | 评论 (1)编辑 收藏

本文主要简述的内容有单例设计模式、dom4j解析xml文件(这里解析的数据库的配置文件)、通过解析出来的配置信息完成数据库的连接。


1、首先要看的是单例设计模式

       单例设计模式的实现有两种:饿汉式(预先加载)、懒汉式(延迟加载),下面分别来看这两种实现方式。

(1)、饿汉式(预先加载)

public class Singleton{
    private static Singleton instance = new Singleton();
    
    private Singleton(){}

    public static synchronized Singleton getInstance(){
        return instance;
    } 
}
(2)懒汉式(延迟加载) 

public class Singleton{
    private static Singleton instance = null;
    
    private Singleton(){}

    public static synchronized Singleton getInstance(){
        if(instance==null){
             instance = new Singleton();
        }
        return instance;
    } 
}

观察上面的这两种模式,看起来区别并不大,前一种方式是类一旦加载就得将对象实例化了,而后一种则是在使用的时候才进行判断是否要实例化对象,并且在后一种的getInstance方法中加入了同步,这样显得更加的合理,个人更加偏好于使用第二种方式。


2、使用dom4j来完成数据库配置文件的解析

给出下面这个数据库的配置文件sys-config.xml


<?xml version="1.0" encoding="UTF-8"?>
<config>
    <db-info>
        <driver>oracle.jdbc.driver.OracleDriver</driver>
        <url>jdbc:oracle:thin:@127.0.0.1:1521:ORCL</url>
        <user>username</user>
        <password>password</password>
    </db-info>
</config>

完成解析的java类:

(1)、保存数据库jdbc配置信息的模型类JdbcConfig.java


package org.ml.drp.util;

/**
 * 用于保存数据库连接时的jdbc参数
 * 
 * 
@author MuLing
 * 
 
*/
public class JdbcConfig {
    private String DbDriver;
    private String DbUrl;
    private String DbUser;
    private String DbPass;

    public String getDbDriver() {
        return DbDriver;
    }

    public void setDbDriver(String dbDriver) {
        DbDriver = dbDriver;
    }

    public String getDbUrl() {
        return DbUrl;
    }

    public void setDbUrl(String dbUrl) {
        DbUrl = dbUrl;
    }

    public String getDbUser() {
        return DbUser;
    }

    public void setDbUser(String dbUser) {
        DbUser = dbUser;
    }

    public String getDbPass() {
        return DbPass;
    }

    public void setDbPass(String dbPass) {
        DbPass = dbPass;
    }

    @Override
    public String toString() {
        return "JdbcConfig [DbDriver=" + DbDriver + ", DbUrl=" + DbUrl
                + ", DbUser=" + DbUser + ", DbPass=" + DbPass + "]";
    }
}

(2)、解析数据库配置文件的工具类XmlConfigReader.java,这里使用单例模式完成,采用的是懒汉式。 

package org.ml.drp.util;

import java.io.InputStream;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
 * 用于解析xml文件 
 * 
@author MuLing
 *
 
*/
public class XmlConfigReader {  
    
    private JdbcConfig jdbcConfig = null;
    private static XmlConfigReader instance = null
    
    private XmlConfigReader(){
        SAXReader reader = new SAXReader();//取得SAXReader的对象
        InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("sys-config.xml");//得到输入流对象
        jdbcConfig = new JdbcConfig();
        Document doc = null;
        try {
            doc = reader.read(input); //进行读取
        } catch (DocumentException e) { 
            e.printStackTrace(); 
        }
                //取得对应的节点对象
               &nbsp;Element driverEle = (Element)doc.selectObject("/config/db-info/driver");
        Element urlEle = (Element)doc.selectObject("/config/db-info/url");
        Element userEle = (Element)doc.selectObject("/config/db-info/user");
        Element passwordEle = (Element)doc.selectObject("/config/db-info/password"); 

        jdbcConfig.setDbDriver(driverEle.getStringValue());
        jdbcConfig.setDbUrl(urlEle.getStringValue());
        jdbcConfig.setDbUser(userEle.getStringValue());
        jdbcConfig.setDbPass(passwordEle.getStringValue()); 
    }
    
    public static synchronized XmlConfigReader getInstance(){
        if(instance==null){
            instance = new XmlConfigReader();
        }
        return instance;
    }
    
    public JdbcConfig getJdbcConfig(){
        return this.jdbcConfig;
    }
}

3、根据解析出了的配置信息完成数据库的连接

下面是一个完成数据库连接操作的测试工具类DbUtil.java


package org.ml.drp.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 封装数据库常用操作类
 * 
@author MuLing
 *
 
*/
public class DbUtil {
  
    /**
     * 取得数据库的连接
     * 
@return
     
*/
    public static Connection getConnection(){
        Connection conn = null;        
        //取得数据库连接字符串
        JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();
        String DBDRIVER = jdbcConfig.getDbDriver();
        String DBURL = jdbcConfig.getDbUrl();
        String DBUSER = jdbcConfig.getDbUser();
        String DBPASS = jdbcConfig.getDbPass();
        //1:注册驱动
        try {
            Class.forName(DBDRIVER);
        } catch (ClassNotFoundException e) { 
            e.printStackTrace();
        }
        //2:获取连接
        try {
            conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
        } catch (SQLException e) { 
            e.printStackTrace();
        }
        //3:返回数据库连接
        return conn;
    }
    
    //测试数据库的连接是否成功
    public static void main(String args[]){ 
        System.out.println(DbUtil.getConnection());
    }
}

上完成了单例模式下使用dom4j来读取数据库配置文件,并实现数据库的连接操作。 




posted @ 2012-08-08 23:37 张慧 阅读(1143) | 评论 (0)编辑 收藏

常有同学想在自己课外学习的安排中,“系统地”学习点什么。这样的事情常发生在喜欢做A专业的事,却上了B专业,且A不等于B,甚至相似度(A, B)趋于无穷。对有些同学,一不留神发现自己的学习落后了不少,比如学计算机的,到大三了,却发现连简单程序也编不出来,再如学完高数了,才知道高数原来如此重要,于是想要系统地重学一遍。
  何为系统学习?系统学习就是要按照已有的一套规定,先学什么,再学什么,按步就班地走完一个流程。为什么要系统学习?将做事能专业些。规定从何而来?业界专家。系统学习有什么好处?基础扎实。系统学习的路线?先理论,再理论指导实践。
  这就怪了。当今大学饱受批评之一在于重理论,轻实践。而到了课外自己的安排,还也要走入这条巷子。深层的原因在于,我们要想学点东西,无意识地延续了一种并不是很合理的思维,学习的模式被单一化了。一边在批评着本专业系统化教学中的弊端,一方面在本来不受约束的自由安排中又要去追求这种系统化,谬矣。
  系统地学,意味着将开始一个比较庞大和长期的计划。雄心勃勃地起步,灰溜溜的,或者不知不觉地停止。这种情况我经历了不止一次。还有一种情况是,祥林嫂式地叨叨一生:“一直想系统学习一下……,却没有机会。”
  要想满足自己的兴趣,其实很简单,用合适的方式行动起来即可。喜欢电子的,先买个套件,备把烙铁,焊个收音机出来;喜欢计算机的,就先自学编个程序出来;喜欢经济的,读些经济学著作……。系统学习的条件往往有些苛刻,所以不要寄望于系统学习。
  实际上,系统学习这个东东,确实用不着为之如此着迷。系统学习本身并没有什么太多的道理,那是对某方面知识的套装,是为了适应大规模人才培养而用的。一旦形成系统,也就意味着僵化,意味着单一标准,在这一套东西广为传播的同时,也为相应的学科进一步发展套上了枷锁,这是一个躲不开的悖论。单按这个系统培养出来的人才,没有特色,缺乏创新,这是现在教育的一个非常大的弊端。
  我们不能直接全盘否认系统学习,这种方法是有效的,也将继续持续。需要我们每个人做的,是不单一地依赖系统化,要突破这个所谓的系统,找出适合自己的办法,进而为这个系统做出贡献。这就是创新。要创新,就一定要有人突破系统的制约。
  一个最简单的问题,各行业都有个祖师爷,哪个祖师爷是科班出身,系统学习过的?在现实中,我们发现很多有所成就的人物往往是多面手,不能说他的每一面都是系统学来的。在职场中,复合型人才受欢迎,复合型人才不可以单一理解为上过几个专业,拿过几个学位。野路子出身,被智叟们看不上的,常常能做出大的成绩。
  在我理想的大学中,同学们的学习将是这样的:他们接受着一项专业教育,一方面由教授系统地传授着专业知识,接受着一种“正规”的训练,另一方面,学生能够根据自己的兴趣、感觉自由地拓展,拓展的内容有的是和系统相关的,有的完全是“节外生枝”。这是课内与课外有效的结合。
  破除“系统学习”的情结,根据自己当前的环境、条件,首先行动起来。在起步时,着重直接的体验,而专门的理论。在整个过程中,看重自己的感受,而不是专家的观点。坚持下来,你将有能力自由出入这个系统,面对的是更为广阔的空间。没有经过系统学习,实在不能不说是一件值得庆幸的事。
  有条件系统学习,或许可以乐一乐;而没有条件系统学习的,一定不要纠结。

  有条件进入了系统学习轨道的,也要常想着“捣乱”,往系统外冲一冲。没有条件以系统学习开始的,不妨在野路子起步,甚至成为高手后,往系统这边看一看,这会让你上到一个新的境界。


总结一下:能进入系统学习轨道的人是幸运的,但也要提防着“系统”给你造成的限制;既然没有条件系统学习的,就不要去干等,先动起来再说。

posted @ 2012-08-08 23:33 张慧 阅读(1371) | 评论 (5)编辑 收藏

2012年8月1日 #

文章的楼主连左值都可以运算,还若无其事得当作可以编译,在那讲解,若无其事就算了,可以当做没有发现编译问题,但是那讲解也太误导人了吧?然后我跟帖的楼下还出现一个“石破天”,以教导式的口吻,在那讲解,不知道的人岂不是就信了吗?真真一群害人之马,当然我只是指其中几位,很多跟帖的朋友,我自认还是不如的。

就为了这个影响广泛的害人帖子(在csdn上弹框出来,影响能不小吗?),我也来探讨一下i++,我是菜鸟,我不会用教导式口吻来讲解。

首先说文章楼主提到的

if((i++=j++)!=4){}  

看到这句代码我真想喷,因为这让我对自己产生了不自信,还去编译了一下,果然是错误的,左边怎么能够进行运算呢?楼主真强大...为什么昨天没有写文章,没有情绪激动,因

为我知道C++风格也是这样赋值,不知道能不能编译过去,但是今天看到跟帖的朋友说,VC98过不去,DEV-C++也过不去,我才感到真有一种被耍的感觉。“左值能运算吗?What  the hell!"这一句,只是骂我自己怀疑自己,没有对其他任何人。

假设,楼主是手误,咱们来一个正确的能编译的代码讨论一下:

int i=4,j=3;   
if((i = j++) != 4) {}  

j++的具体动作应该是怎样的,我想看过《Thinking in Java》的朋友都掌握得还不错,如果实在想找更深入一点探讨i++的书,个人看过《Java程序员面试宝典》,里面有提到i++这个部分,讲得很仔细。j++,是一个依赖于java里面的“中间缓存变量机制”来实现的,很多人都会念++在前就是“先加后赋”,++在后就是“先赋后加”,但是这个“赋”和这个“加”是针对哪个对象呢,有几个人能清楚的解释?“宝典”这本书上面的解释,个人觉得非常好,就来这里秀一段。首先,像文章中2楼所说那样:++的时间是以整个语句为衡量的,所以,什么时候自增,跟一整句运算语句有关,现在的情况是 i = j++:这样一句应该被拆分为:

 

temp = j;//先赋
j = j + 1;//后加
i = temp;

 

再来一个i = ++j:这一句应该被拆分为:

j = j + 1;//先加
temp = j;//后赋
i = temp;

用这样的语句,来解释“赋”跟“加”应该是很明了的吧?记住,“加”只涉及了本身,“赋”涉及本身和中间缓存变量。

如何理解“++的时间是以整个语句为衡量的”?咱们来一段复杂的就可以很好地理解了,就拿那个被我喷的“石破天”的吧。

 

/* 这个是原式,尊重版权,但是误导人*/
int i=10;
i=i++ + i++;//20  --这里应该会是21,note by jacob
i=++i + ++i;//44  --这里应该会是45,note by jacob
 

 

首先咱们把这都拆开来理解:

/* 细说第一个 i = i++ + i ++; */
temp1 = i;//temp1 == 10
i = i + 1;//i == 11;
temp2 = i;//temp2 == 11
i = i + 1;//i == 12;
i = temp1 + temp2;//i == 21

/*第二个 i = ++i + ++i;*/
i = i + 1;
temp1 = i;
i = i + 1;
temp2 = i;
i = temp1 +temp2;


这样的例子,应该算是比较复杂的吧?如果需要,还可以来一个更加复杂的,不过不再详细解释,大家可以拿来推敲一下:

int j =0,k = 0,h=0;
k = k++ + k++ + k++ + ++k;//k == 7
j = ++j + j++ + j++ + j++;//j ==7;
h = ++h + ++h;
posted @ 2012-08-01 21:56 张慧 阅读(2658) | 评论 (1)编辑 收藏

 这段时间遇到一个问题:使用ajax生成一个列表,然后使用sorttable.js对这个列表进行排序。问题在于:生成的列表还没出现,排序已经开始了,结果没有找到列表报错。解决方法: 
 function ifExist(table){
    if(table.tBodies[0]==null)
   {
  setTimeout( function(){ifExist(table);}, 1000);  
   }
   else
   {
  sorttable.makeSortable(table);
   }
 }

判断节点是否生成了,如果没有,那么就等待1秒,再循环执行。一切ok了!

 

最后,补充一下关于javascript同步和异步的问题(转载):

一、同步加载与异步加载的形式
1. 同步加载
我们平时最常使用的就是这种同步加载形式:
<script src="http://yourdomain.com/script.js"></script> 
同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。
js 之所以要同步执行,是因为 js 中可能有输出 document 内容、修改dom、重定向等行为,所以默认同步执行才是安全的。
以前的一般建议是把<script>放在页面末尾</body>之前,这样尽可能减少这种阻塞行为,而先让页面展示出来。
简单说:加载的网络 timeline 是瀑布模型,而异步加载的 timeline 是并发模型。

2. 常见异步加载(Script DOM Element)

(function() {      var s = document.createElement('script');      s.type = 'text/javascript';      s.async = true;      s.src = 'http://yourdomain.com/script.js';      var x = document.getElementsByTagName('script')[0];      x.parentNode.insertBefore(s, x);  })();

异步加载又叫非阻塞,浏览器在下载执行 js 同时,还会继续进行后续页面的处理。
这种方法是在页面中<script>标签内,用 js 创建一个 script 元素并插入到 document 中。这样就做到了非阻塞的下载 js 代码。
async属性是HTML5中新增的异步支持,见后文解释,加上好(不加也不影响)。
此方法被称为 Script DOM Element 法,不要求 js 同源。
将js代码包裹在匿名函数中并立即执行的方式是为了保护变量名泄露到外部可见,这是很常见的方式,尤其是在 js 库中被普遍使用。
例如 Google Analytics 和 Google+ Badge 都使用了这种异步加载代码:
(function() {      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);  })();  
(function()
    {var po = document.createElement("script");     po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";     var s = document.getElementsByTagName("script")[0];     s.parentNode.insertBefore(po, s);  })();  
但是,这种加载方式在加载执行完之前会阻止 onload 事件的触发,而现在很多页面的代码都在 onload 时还要执行额外的渲染工作等,所以还是会阻塞部分页面的初始化处理。

3. onload 时的异步加载

(function() {      function async_load(){          var s = document.createElement('script');          s.type = 'text/javascript';          s.async = true;          s.src = 'http://yourdomain.com/script.js';          var x = document.getElementsByTagName('script')[0];          x.parentNode.insertBefore(s, x);      }      if (window.attachEvent)          window.attachEvent('onload', async_load);      else          window.addEventListener('load', async_load, false);  })();  
这和前面的方式差不多,但关键是它不是立即开始异步加载 js ,而是在 onload 时才开始异步加载。这样就解决了阻塞 onload 事件触发的问题。
补充:DOMContentLoaded 与 OnLoad 事件
DOMContentLoaded : 页面(document)已经解析完成,页面中的dom元素已经可用。但是页面中引用的图片、subframe可能还没有加载完。
OnLoad:页面的所有资源都加载完毕(包括图片)。浏览器的载入进度在这时才停止。
这两个时间点将页面加载的timeline分成了三个阶段。

4.异步加载的其它方法

由于Javascript的动态特性,还有很多异步加载方法:
  • XHR Eval
  • XHR Injection
  • Script in Iframe
  • Script Defer
  • document.write Script Tag
  • 还有一种方法是用 setTimeout 延迟0秒 与 其它方法组合。
XHR Eval :通过 ajax 获取js的内容,然后 eval 执行。
var xhrObj = getXHRObject();   xhrObj.onreadystatechange =      function() {        if ( xhrObj.readyState != 4 ) return;       eval(xhrObj.responseText);     };   xhrObj.open('GET', 'A.js', true);   xhrObj.send('');  
Script in Iframe:创建并插入一个iframe元素,让其异步执行 js 。
var iframe = document.createElement('iframe');   document.body.appendChild(iframe);   var doc = iframe.contentWindow.document;   doc.open().write('<body onload="insertJS()">');   doc.close();  
GMail Mobile:页内 js 的内容被注释,所以不会执行,然后在需要的时候,获取script元素中 text 内容,去掉注释后 eval 执行。
<script type="text/javascript">   /*   var ...    */   </script>  
详见参考资料中2010年的Velocity 大会 Steve Souders 和淘宝的那两个讲义。
二、async 和 defer 属性
1. defer 属性
<script src="file.js" defer></script> 
defer属性声明这个脚本中将不会有 document.write 或 dom 修改。
浏览器将会并行下载 file.js 和其它有 defer 属性的script,而不会阻塞页面后续处理。
defer属性在IE 4.0中就实现了,超过13年了!Firefox 从 3.5 开始支持defer属性 。
注:所有的defer 脚本保证是按顺序依次执行的。
2. async 属性
<script src="file.js" async></script> 
async属性是HTML5新增的。作用和defer类似,但是它将在下载后尽快执行,不能保证脚本会按顺序执行。它们将在onload 事件之前完成。
Firefox 3.6、Opera 10.5、IE 9 和 最新的Chrome 和 Safari 都支持 async 属性。可以同时使用 async 和 defer,这样IE 4之后的所有 IE 都支持异步加载。
3. 详细解释
<script> 标签在 HTML 4.01 与 HTML5 的区别:
  • type 属性在HTML 4中是必须的,在HTML5中是可选的。
  • async 属性是HTML5中新增的。
  • 个别属性(xml:space)在HTML5中不支持。
说明:
  1. 没有 async 属性,script 将立即获取(下载)并执行,然后才继续后面的处理,这期间阻塞了浏览器的后续处理。
  2. 如果有 async 属性,那么 script 将被异步下载并执行,同时浏览器继续后续的处理。
  3. HTML4中就有了defer属性,它提示浏览器这个 script 不会产生任何文档元素(没有document.write),因此浏览器会继续后续处理和渲染。
  4. 如果没有 async 属性 但是有 defer 属性,那么script 将在页面parse之后执行。
  5. 如果同时设置了二者,那么 defer 属性主要是为了让不支持 async 属性的老浏览器按照原来的 defer 方式处理,而不是同步方式。
另参见官方说明:script async
个人补充:
既然 HTML5 中已经支持异步加载,为什么还要使用前面推荐的那种麻烦(动态创建 script 元素)的方式?
答:为了兼容尚不支持 async 老浏览器。如果将来所有浏览器都支持了,那么直接在script中加上async 属性是最简单的方式。
三、延迟加载(lazy loading)
前面解决了异步加载(async loading)问题,再谈谈什么是延迟加载。
延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的。延迟加载就是一开始并不加载这些暂时不用的js,而是在需要的时候或稍后再通过js 的控制来异步加载。
也就是将 js 切分成许多模块,页面初始化时只加载需要立即执行的 js ,然后其它 js 的加载延迟到第一次需要用到的时候再加载。
特别是页面有大量不同的模块组成,很多可能暂时不用或根本就没用到。
就像图片的延迟加载,在图片出现在可视区域内时(在滚动条下拉)才加载显示图片。
四、script 的两阶段加载 与 延迟执行(lazy execution)
JS的加载其实是由两阶段组成:下载内容(download bytes)和执行(parse and execute)。
浏览器在下载完 js 的内容后就会立即对其解析和执行,不管是同步加载还是异步加载。
前面说的异步加载,解决的只是下载阶段的问题,但代码在下载后会立即执行。
而浏览器在解析执行 JS 阶段是阻塞任何操作的,这时的浏览器处于无响应状态。
我 们都知道通过网络下载 script  需要明显的时间,但容易忽略了第二阶段,解析和执行也是需要时间的。script的解析和执行所花的时间比我们想象的要多,尤其是script  很多很大的时候。有些是需要立刻执行,而有些则不需要(比如只是在展示某个界面或执行某个操作时才需要)。
这些script 可以延迟执行,先异步下载缓存起来,但不立即执行,而是在第一次需要的时候执行一次。
利用特殊的技巧可以做到 下载 与 执行的分离 (再次感谢 javascript 的动态特性)。比如将 JS 的内容作为 Image或 object 对象加载缓存起来,所以就不会立即执行了,然后在第一次需要的时候再执行。
此部分的更多解释 请查看末尾参考资料中 ControlJS 的相关链接。
小技巧:
1. 模拟较长的下载时间
写个后端脚本,让其 sleep 一定时间。如在 jsp 中 Thread.sleep(5000); ,这样5秒后才能收到内容。
2. 模拟较长的 js 代码执行时间(因为这步一般比较快不容易观察到):
var t_start = Number(new Date());
while ( t_start + 5000 > Number(new Date()) ) {}
这个代码将使 js 执行5秒才能完成!
五、script 标签使用的历史

1. script 放在 HEAD 中
<head>   <script src=“…”></script>   </head>  
  • 阻止了后续的下载;
  • 在IE 6-7 中 script 是顺序下载的,而不是现在的 “并行下载、顺序执行” 的方式;
  • 在下载解析执行阶段阻止渲染(rendering);
2. script 放在页面底部(2007)
...   <script src=“…”></script>   </body>  
  • 不阻止其它下载;
  • 在IE 6-7 中 script 是顺序下载的;
  • 在下载解析执行阶段阻止渲染(rendering);
3. 异步加载script(2009)
var se = document.createElement  ('script');   se.src = 'http://anydomain.com/A.js';   document.getElementsByTagName('head')   [0].appendChild(se);  
这就是本文主要说的方式。
  • 不阻止其它下载;
  • 在所有浏览器中,script都是并行下载;
  • 只在解析执行阶段阻止渲染(rendering);
4. 异步下载 + 按需执行 (2010)
var se = new Image();   se.onload = registerScript();   se.src = 'http://anydomain.com/A.js';  把下载 js 与 解析执行 js 分离出来
  • 不阻止其它下载;
  • 在所有浏览器中,script都是并行下载;
  • 不阻止渲染(rendering)直到真正需要时;
六、异步加载的问题
在异步加载的时候,无法使用 document.write 输出文档内容。
在同步模式下,document.write 是在当前 script 所在的位置输 出文档的。而在异步模式下,浏览器继续处理后续页面内容,根本无法确定 document.write  应该输出到什么位置,所以异步模式下 document.write 不可行。而到了页面已经 onload  之后,再执行 document.write 将导致当前页面的内容被清空,因为它会自动触发 document.open 方法。
实际上document.write的名声并不好,最好少用。
替代方法:
1. 虽然异步加载不能用 document.write,但还是可以onload之后执行操作dom(创建dom或修改dom)的,这样可以实现一些自己的动态输出。比如要在页面异步创建一个浮动元素,这和它在页面中的位置就没关系了,只要创建出该dom元素添加到 document 中即可。
2. 如果需要在固定位置异步生成元素的内容,那么可以在该固定位置设置一个dom元素作为目标,这样就知道位置了,异步加载之后就可以对这个元素进行修改。
六、JS 模块化管理
异步加载,需要将所有 js 内容按模块化的方式来切分组织,其中就存在依赖关系,而异步加载不保证执行顺序。
另外,namespace 如何管理 等相关问题。这部分已超出本文内容,可参考:
RequireJS 、 CommonJS 以及 王保平(淘宝)的 SeaJS 及其博客 。
七、JS最佳实践:
1. 最小化 js 文件,利用压缩工具将其最小化,同时开启http gzip压缩。工具:
2. 尽量不要放在 <head> 中,尽量放在页面底部,最好是</body>之前的位置
3. 避免使用 document.write 方法
4. 异步加载 js ,使用非阻塞方式,就是此文内容。
5. 尽量不直接在页面元素上使用 Inline Javascript,如onClick 。有利于统一维护和缓存处理。

posted @ 2012-08-01 21:50 张慧 阅读(8385) | 评论 (0)编辑 收藏

使用谷歌jquery库文件的理由
近前端开发看到,那些引用jquery的文件那些网站,好多是使用谷歌的库;像这样的<script type=”text/javascript”src=”http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js“></script>(最近发展到1.7.1版本的,好神速呐,前两天还看到一哥们用的1.2.6感慨啊。。。。)
像上面这样加载jquery通过谷歌的CDN-Content Delivery Network(内容分发网络)来让你的网站加载jquery库文件。有的同学可能会问了,为什么要加载谷歌的jquery库文件呢?(PS:我们一般不 都是加载自己服务器上的jquery库文件的吗?)。呵呵~~之前也和大家一样想的,也一直都是加载自己的服务器上的jquery文件。
下面我来和大家说说,使用谷歌加载jquery库文件的好处。
1,增加网页的同时载入速度
为了避免服务的过载,浏览器限制了同时连接的数目,依据不同的浏览器,这个限制可能是每个机房仅仅两个之少。
使用谷歌的AJAX内容服务网络来响应你的网站,使你本地服务器上更多服务可以同时进行。
2,减少等待时间
大家应该也差不多,在感慨jquery的强大,也在感慨jquery的团队也是如此之强大,呵呵~现在最新的jquery已经出到1.7.1版本了呢,但是让人很不爽的是即使是mini压缩过后的代码都有83.2KB。但是不知道大家有没有去官方首页看过。
CDN-Content Delivery Network(内容分发网络)的缩写,通过各种各样的服务途径把你的一些静态内容分散开来,当用户的浏览器提交这些文件的链接请求,他们便会自动下载网络上最近的可用的文件。
因为这个原因:任何使用你的服务的用户从谷歌下载JQuery库都将获得比从你自己的服务器上下载更快的速度。其实有很多的CDN服务可与谷歌的相比拟,但是他们很难超越谷歌的免费服务的优势,这个益处足以决定问题,但这仅仅是一部分。
3,更好的缓存
利用谷歌AJAX图书馆内容发布服务的最大好处是你的用户根本不需要下载jQuery. 不论你的缓存多么强大,如果你用自己的服务器提供jQuery,那么你的用户至少要下载一次它,某个用户很有可能在他们浏览器的缓存区里下载了许多完全相 同的jQuery.min.js的拷贝版本,但是当他们第一次访问你的网站的时候,这些拷贝版本会被忽略。
另一方面,当浏览器检测到同样版本的指向谷歌的链接,它就会知道这是下载同一个文件,不仅是谷歌的服务器会返回一个304(不需要修改文件的指令,即服务器上的文件未改动过)来回复一个重复的请求,而且会命令浏览器的缓存该文件长达一年的时间。http://www.jqueryba.com/14.html
这意味着即使一些人访问了数百的使用谷歌服务的jQuery网站,他们只需要下载一次就够了。
不过好像最近天朝对谷歌的东西有点反感呀,就像以前谷歌生气出走香港一样,有的时候谷歌的东西会打不开,那么会不会有一天使用这种方式加载jquery库文件也会失败呢?呵呵~~万事皆有可能,呵呵~不要紧,此处有一个万全的方法:
 <script type=text/javascript src=”http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js”></script>
<script>!window.jQuery && document.write(‘<script src=”jquery-1.7.1.min.js”><\/script >’);</script>
将上面的代码放到你的html代码的头部。意义是这样的:首先去加载谷歌的jquery库文件,如果没有加载成功的话,那么就只好加载自己服务器上的jquery库文件咯。
posted @ 2012-08-01 21:43 张慧 阅读(1063) | 评论 (1)编辑 收藏