<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    張慧的博客

    張慧的博客

      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 張慧 閱讀(1416) | 評論 (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 張慧 閱讀(2983) | 評論 (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 張慧 閱讀(746) | 評論 (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 張慧 閱讀(1660) | 評論 (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 張慧 閱讀(3378) | 評論 (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 張慧 閱讀(7768) | 評論 (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 張慧 閱讀(6918) | 評論 (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 張慧 閱讀(1663) | 評論 (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 張慧 閱讀(1341) | 評論 (0)編輯 收藏

    常有同學想在自己課外學習的安排中,“系統地”學習點什么。這樣的事情常發生在喜歡做A專業的事,卻上了B專業,且A不等于B,甚至相似度(A, B)趨于無窮。對有些同學,一不留神發現自己的學習落后了不少,比如學計算機的,到大三了,卻發現連簡單程序也編不出來,再如學完高數了,才知道高數原來如此重要,于是想要系統地重學一遍。
      何為系統學習?系統學習就是要按照已有的一套規定,先學什么,再學什么,按步就班地走完一個流程。為什么要系統學習?將做事能專業些。規定從何而來?業界專家。系統學習有什么好處?基礎扎實。系統學習的路線?先理論,再理論指導實踐。
      這就怪了。當今大學飽受批評之一在于重理論,輕實踐。而到了課外自己的安排,還也要走入這條巷子。深層的原因在于,我們要想學點東西,無意識地延續了一種并不是很合理的思維,學習的模式被單一化了。一邊在批評著本專業系統化教學中的弊端,一方面在本來不受約束的自由安排中又要去追求這種系統化,謬矣。
      系統地學,意味著將開始一個比較龐大和長期的計劃。雄心勃勃地起步,灰溜溜的,或者不知不覺地停止。這種情況我經歷了不止一次。還有一種情況是,祥林嫂式地叨叨一生:“一直想系統學習一下……,卻沒有機會。”
      要想滿足自己的興趣,其實很簡單,用合適的方式行動起來即可。喜歡電子的,先買個套件,備把烙鐵,焊個收音機出來;喜歡計算機的,就先自學編個程序出來;喜歡經濟的,讀些經濟學著作……。系統學習的條件往往有些苛刻,所以不要寄望于系統學習。
      實際上,系統學習這個東東,確實用不著為之如此著迷。系統學習本身并沒有什么太多的道理,那是對某方面知識的套裝,是為了適應大規模人才培養而用的。一旦形成系統,也就意味著僵化,意味著單一標準,在這一套東西廣為傳播的同時,也為相應的學科進一步發展套上了枷鎖,這是一個躲不開的悖論。單按這個系統培養出來的人才,沒有特色,缺乏創新,這是現在教育的一個非常大的弊端。
      我們不能直接全盤否認系統學習,這種方法是有效的,也將繼續持續。需要我們每個人做的,是不單一地依賴系統化,要突破這個所謂的系統,找出適合自己的辦法,進而為這個系統做出貢獻。這就是創新。要創新,就一定要有人突破系統的制約。
      一個最簡單的問題,各行業都有個祖師爺,哪個祖師爺是科班出身,系統學習過的?在現實中,我們發現很多有所成就的人物往往是多面手,不能說他的每一面都是系統學來的。在職場中,復合型人才受歡迎,復合型人才不可以單一理解為上過幾個專業,拿過幾個學位。野路子出身,被智叟們看不上的,常常能做出大的成績。
      在我理想的大學中,同學們的學習將是這樣的:他們接受著一項專業教育,一方面由教授系統地傳授著專業知識,接受著一種“正規”的訓練,另一方面,學生能夠根據自己的興趣、感覺自由地拓展,拓展的內容有的是和系統相關的,有的完全是“節外生枝”。這是課內與課外有效的結合。
      破除“系統學習”的情結,根據自己當前的環境、條件,首先行動起來。在起步時,著重直接的體驗,而專門的理論。在整個過程中,看重自己的感受,而不是專家的觀點。堅持下來,你將有能力自由出入這個系統,面對的是更為廣闊的空間。沒有經過系統學習,實在不能不說是一件值得慶幸的事。
      有條件系統學習,或許可以樂一樂;而沒有條件系統學習的,一定不要糾結。

      有條件進入了系統學習軌道的,也要常想著“搗亂”,往系統外沖一沖。沒有條件以系統學習開始的,不妨在野路子起步,甚至成為高手后,往系統這邊看一看,這會讓你上到一個新的境界。


    總結一下:能進入系統學習軌道的人是幸運的,但也要提防著“系統”給你造成的限制;既然沒有條件系統學習的,就不要去干等,先動起來再說。

    posted @ 2012-08-08 23:33 張慧 閱讀(1488) | 評論 (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 張慧 閱讀(2827) | 評論 (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 張慧 閱讀(9037) | 評論 (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 張慧 閱讀(1151) | 評論 (1)編輯 收藏

    主站蜘蛛池模板: 国产亚洲精品不卡在线| 亚洲a级片在线观看| 四虎成人精品一区二区免费网站 | 国产免费人成视频在线播放播| 亚洲中文字幕不卡无码| 一个人看的www免费视频在线观看| 伊人久久免费视频| 国产精品无码免费播放| 亚洲视频中文字幕| 十八禁视频在线观看免费无码无遮挡骂过| 免费国产污网站在线观看| 免费不卡视频一卡二卡| 亚洲人成电影在线观看网| 污视频网站在线免费看| 亚洲国产一区二区三区| 国产高潮久久免费观看| 亚洲免费二区三区| 国产成人亚洲精品| 日本免费一二区在线电影| 亚洲成人免费在线观看| 亚洲大香人伊一本线| 亚洲日韩精品A∨片无码加勒比| 一级做a爰片性色毛片免费网站| 免费无码又爽又刺激高潮视频| 精品国产免费人成网站| 国产精品成人免费综合| 暖暖免费高清日本一区二区三区| 亚洲中文字幕无码专区| 亚洲中文无码mv| 免费无码又爽又高潮视频| 亚洲日本va在线视频观看| 亚洲午夜精品久久久久久浪潮| 精品亚洲麻豆1区2区3区| 男男gay做爽爽免费视频| 日产国产精品亚洲系列| 亚洲精品日韩中文字幕久久久| 久久免费视频观看| 久久不见久久见中文字幕免费| 亚洲午夜精品一级在线播放放 | 亚洲色成人网站WWW永久| 在线观看肉片AV网站免费|