jarry998812

jarry998812的博客

513-384-8151

              |
网址          | URL
网址128位MD5  | UrlMD5
IP地址        | IP
采集内容      | content
页面类型      | type
              |


采集流程图
-------------------------------

 初始化:载入已经采集的UrlMD5
|-------------------------------------------------------------------------------------------------------|
|Spiderç±»                                                                                               |
|         |---------------------------------------------------------------------|    |----------------| |
|  |--|   |采集通道(线程)                         ------------------------------|--->| 已采集UrlMD5池 | |
|  |种|   |      |---------|    |--------|    |---|------|     |--------|       |    |----------------| |
|  |子|---|---|->| URL队列 |--->| 采集器 |--->|   |  |   |---->| 分析器 |---|   |                       |
|  |队|   |   |  |---------|    |--------|    |------|---|     |--------|   |   |                       |
|  |列|   |   |                                      |                      |   |                       |
|  |--|   |   |--------------------------------------|----------------------|   |    |----------------| |
|    |---<|                                          ---------------------------|--->| 已采集内容队列 | |
|    |    |---------------------------------------------------------------------|    |--------|-------| |
|    |                                                                                        |         |
|    |    |---------|                                                                         |         |
|    |---<|存储线程 |<------------------------------------------------------------------------|         |
|    |    |---------|                                                                                   |
|    |                                                                                                  |
|    |    |---------|                                                                                   |
|    |--->|日志线程 |                                                                                   |
|         |---------|                                                                                   |
|                                                                                                       |
|-------------------------------------------------------------------------------------------------------|


类设计
-------------------------------
控制器类
  SpiderHandler -- 控制台入口

采集核心类
  Spider     核心
  PageInfo   基础--数据结构
  Gatherer   基础--网页采集器
  Analyser   基础--url分析器

外部接口
  IStorage   数据存储接口
  ISpiderUI  用户界面
  ILogger    日志接口

*/

/==================================================================
/
/    该软件是一个由C#编写的基于控制台的多线程网页自动采集程序。
/    又称之为蜘蛛,机器人,爬行器等。
/
/    Copyright(C) 2009 themz.cn All rights reserved
/    author:   xml
/    email:    191081370@qq.com
/    blog:     /programmingcanruinyourlife.themz.cn/
/    since:    .net2.0
/    version:  1.0
/    created:  2009-08-06
/    modified: 2009-10-10
/
/  版权与免责声明:本软件所有权归原作者,用户可自由免费使用于任何非商业环境。
/                  如果转载本文代码请不要删除这段版权声明。
/                  如果由于使用本软件而造成自己或他人的任何损失,均与本软件作者无关。
/                  特此声明!
/
/==================================================================
/    简单使用帮助:
/         1. 将下面代码保存到一个.cs后缀的文件中
/         2. 用.net2.0的编译环境编译成一个exe文件后,双击打开
/         3. 用 addSeeds命令添加采集种子, 例如: addSeeds /url/
/         4. 用 start 命令开始采集
/         5. 反复使用 getContents 命令查看已采集到的内容
/         6. pause 命令可暂停采集, start 命令继续
/         7. stop 命令停止采集
/         8. exit 命令退出本软件
/
/

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

/using System.Configuration;
/using System.Diagnostics;
/[Serializable()]
namespace My.WSE.Spider
{
  #region 线程模式接口
    /**
    线程类模式

    接口  参数

    队列  属性
    线程  属性

    入队  方法
    出队  方法

    增加/启动  方法
    暂停       方法
    停止       方法
    */
    public interface IThread
    {
        /T Queue{ get; }
        /List<Thread> Threads{ get; }
        /
        /void Enqueue( T t );
        /T Dequeue();

        Thread AddThread();
        void RemoveThread();
        void RequestThreadPause();
        void RequestThreadPause( bool pauseOrContinue );
        void RequestThreadStop();
    }
  #endregion

  #region  外部接口
    / 采集接口
    public interface IGatherer
    {
        void Download( ref PageInfo info,string contentType,int timeout );
        void Download( ref PageInfo info,int timeout );
    }

    / 存储接口
    public interface IStorage
    {
        List<string> GetIndexeds();                      /取得所有已下载的URL的MD5值

        List<SeedInfo> GetSeeds();
        int AddSeed( SeedInfo info );
        void RemoveSeed( SeedInfo info );

        void SaveContents( List<PageInfo> info );        /保存采集到的内容
    }

    / 日志接口
    public interface ILogger
    {
        void Write( string content );
        string Read( string filename );

        string ToString( Exception ex );
    }

  #endregion

  #region 异常类
    public class ContentTypeException : Exception
    {
        public ContentTypeException( string message ) : base( message ){}
    }

    public class ContentSizeException : Exception
    {
        public ContentSizeException( string message ) : base( message ){}
    }

    public class NotOnlyException : Exception
    {
        public NotOnlyException( string message ) : base( message ){}
    }

    public class KeyHasExistsException : Exception
    {
        public KeyHasExistsException( string message ) : base( message ){}
    }
  #endregion

  #region PageInfo队列
    public class PageQueue
    {
        / 构造函数1
        public PageQueue()
        {
            _queue = new LinkedList<string>();
        }
        / 构造函数2
        public PageQueue( ref LinkedList<string> queue ) : this()
        {
            if( null != queue ){
                _queue = queue;
            }
        }


      #region 队列方法
        public int Count
        {
            get{  return _queue.Count;  }
        }
        public bool Contains( PageInfo info )
        {
            return _queue.Contains( info.UrlMD5 );
        }
        public void Enqueue( PageInfo info )   /等同于AddLast
        {
            AddLast( info );
        }
        public PageInfo Dequeue()              /等同于RemoveFirst
        {
            return RemoveFirst();
        }

        public void AddFirst( PageInfo info )
        {
            lock( _queue ){
                _queue.AddFirst( info.UrlMD5 );
                AddData( info );
                Monitor.Pulse( _queue );
            }
        }
        public void AddLast( PageInfo info )
        {
            lock( _queue ){
                _queue.AddLast( info.UrlMD5 );
                AddData( info );
                Monitor.Pulse( _queue );
            }
        }
        public PageInfo RemoveFirst()
        {
            PageInfo info = null;
            lock( _queue ){
                LinkedListNode<string> node = _queue.First;
                if( null == node ){
                    Monitor.Wait( _queue );
                    node = _queue.First;
                }

                string key = node.Value;
                _queue.RemoveFirst();
                info = GetData(key);
                RemoveData(key);    / 释放内存中的数据
            }
            return info;
        }
        public PageInfo RemoveLast()
        {
            PageInfo info = null;
            lock( _queue ){
                LinkedListNode<string> node = _queue.First;
                if( null == node ){
                    Monitor.Wait( _queue );
                }
                else{
                    string key = node.Value;
                    _queue.RemoveFirst();
                    info = GetData(key);
                    RemoveData(key);    / 释放内存中的数据
                }
            }
            return info;
        }
        public PageInfo Remove( PageInfo info )
        {
            lock( _queue ){
                if( _queue.Remove(info.UrlMD5) ){
                    info = GetData(info.UrlMD5);
                    RemoveData(info.UrlMD5);    / 释放内存中的数据
                }
                else{
                    info = null;
                }
            }
            return info;
        }

        public Dictionary<string,PageInfo> ToDictionary()
        {
            Dictionary<string,PageInfo> dict = new Dictionary<string,PageInfo>();

            lock( _queue ){
                LinkedListNode<string> node = _queue.First;
                while( null != node ){
                    dict[node.Value] = GetData(node.Value);
                    node = node.Next;
                }
            }
            return dict;
        }
      #endregion

      #region 词典方法
        public PageInfo GetData( string key )
        {
            lock( _s_pages ){
                if( _s_pages.ContainsKey(key) ){
                    return _s_pages[key];
                }else{
                    _log.Enqueue( string.Format( "wse.spider.cs GetData,Dictionary键{0}没有找到",key) );
                    return null;
                }
            }
        }
        public void AddData( PageInfo info )
        {
            lock( _s_pages ){
                _s_pages[info.UrlMD5] = info;
            }
        }
        public void RemoveData( string key )
        {
            lock( _s_pages ){
                if( _s_pages.ContainsKey(key) ){
                    _s_pages.Remove(key);
                }
            }
        }
        public bool ContainsData( PageInfo info )
        {
            return _s_pages.ContainsKey(info.UrlMD5);
        }
      #endregion

      #region Private Members

        private LinkedList<string> _queue = null;
        private static Dictionary<string,PageInfo> _s_pages = new Dictionary<string,PageInfo>();

        private EventLogger _log = new EventLogger();
      #endregion
    }
  #endregion

  #region 采集线程类
    public class PageGatherer : IThread
    {
      #region 构造函数
        / 构造函数1
        public PageGatherer(){}

        / 构造函数2
        public PageGatherer( IGatherer gather )
        {
            _log = new EventLogger();
            _store = new PageStorage();

            _gather = gather;
            _queue = new PageQueue();        / 每个队列可以
            _threads = new List<Thread>();   / 有多个线程

            _shouldPause = new ManualResetEvent(true);
            _shouldStop = false;
        }
      #endregion

      #region Public Property
        / 静态成员公开
        public Dictionary<string,string> IndexedPool
        {
            get{ return _s_indexedPool; }
        }
        public PageQueue SeedQueue
        {
            get{  return _s_seedQueue;  }
        }

        / 当前采集队列
        public PageQueue Queue
        {
            get{  return _queue;  }
        }
        public List<Thread> Threads
        {
            get{  return _threads;  }
        }
        / 线程总数
        public int ThreadCount
        {
            get{  return _threadCount;  }
        }
      #endregion

      #region 线程方法(Thread Method)
        / 增加线程
        public Thread AddThread()
        {
            Thread t = new Thread( new ThreadStart(ThreadRun) );
            t.IsBackground = true;
            t.Start();
            _threads.Add(t);
            _threadCount++;
            return t;
        }
        / 减少线程
        public void RemoveThread()
        {
            / 尚未实现
        }
        / 请求线程暂停
        public void RequestThreadPause()
        {

        }
        / 请求线程继续
        public void RequestThreadPause( bool pauseOrContinue )
        {
            if( !pauseOrContinue ){
                _shouldPause.Set();
            }else{
                _shouldPause.Reset();
            }
        }
        / 请求线程停止
        public void RequestThreadStop()
        {
            _shouldStop = true;
        }
      #endregion

      #region Private Methods
        / 采集线程方法
        private void ThreadRun()
        {
            PageInfo info = null;

            / 循环: URL->下载->存储->分析->|URL->下载....
            while( !_shouldStop )
            {
                _shouldPause.WaitOne();              / 是否暂停
                if( _queue.Count < 1 ){
                    _queue.Enqueue( _s_seedQueue.Dequeue() );     / 自动取得种子
                }

                info = _queue.Dequeue();
                if( null == info ){  continue;  }

                /1 下载
                string url = info.URL;
                try{
                    _gather.Download(ref info,"text/html",90000);
                }
                catch( Exception ex ){
                    _log.Enqueue( info.URL + " " + ex.ToString() );
                    continue;
                }

                /2 把当前url加入_s_indexedPool
                AddIndexed( info.UrlMD5 );

                /3 保存:加入_dataPool
                _store.Queue.Enqueue( info );

                /4 分析:加入下载队列queue
                AnalyzeToQueue( info, ref _queue );
            }
        }
        / 分析出页面中的url,并把它们加进队列中
        private void AnalyzeToQueue( PageInfo info, ref PageQueue queue )
        {
            PageQueue _queue = queue;

            List<string[]> urls = Analyzer.ParseToURLs(info);
            PageInfo newInfo = null;

            for( int i=0,len=urls.Count; i<len; i++ ){
                newInfo = new PageInfo( urls[i][0],info.SeedID );

                if( !_queue.ContainsData(newInfo) && !_s_indexedPool.ContainsKey(newInfo.UrlMD5) ){
                    newInfo.Title = urls[i][1];
                    newInfo.Referer = info.URL;

                    _queue.Enqueue( newInfo );
                }
            }
        }
        / 加入已采集队列
        private void AddIndexed( string urlMD5 )
        {
            lock( _s_indexedPool ){
                if( !_s_indexedPool.ContainsKey(urlMD5) ){
                    _s_indexedPool.Add( urlMD5, null );
                }
            }
        }
      #endregion

      #region Private Members
        private EventLogger _log = null;
        private PageStorage  _store = null;

        private IGatherer _gather = null;       / 接口
        private PageQueue _queue;               / 每个队列可以
        private List<Thread> _threads;          / 有多个线程

        private ManualResetEvent _shouldPause;  / 暂停
        private bool _shouldStop;               / 停止

        private static Dictionary<string,string> _s_indexedPool = new Dictionary<string,string>();      / 已采集的URL
        private static PageQueue _s_seedQueue = new PageQueue();   / 种子队列

        private static int _threadCount = 0;     / 运行的线程的总数
      #endregion
    }
  #endregion

  #region 存储线程类
    public class PageStorage  : IThread
    {
      #region 构造函数
        / 构造函数1
        public PageStorage(){}

        / 构造函数2
        public PageStorage( IStorage store )
        {
            _log = new EventLogger();

            _store = store;
            _shouldStop = false;
        }
      #endregion

      #region Public Property
        / 对列对象
        public PageQueue Queue
        {
            get{ return _s_queue;  }
        }
        / 线程对象集合
        public List<Thread> Threads
        {
            get{ return _threads;  }
        }
      #endregion

      #region 线程方法(Thread Method)
        / 增加线程
        public Thread AddThread()
        {
            Thread t = new Thread( new ThreadStart(ThreadRun) );
            t.IsBackground = true;
            t.Start();
            return t;
        }
        / 减少线程
        public void RemoveThread()
        {
            / 尚未实现
        }
        / 请求线程暂停
        public void RequestThreadPause()
        {
            / 尚未实现
        }
        / 请求线程继续
        public void RequestThreadPause( bool pauseOrContinue )
        {
            / 尚未实现
        }
        / 请求线程停止
        public void RequestThreadStop()
        {
            _shouldStop = true;
        }
      #endregion

      #region Private Methods
        / 线程方法
        private void ThreadRun()
        {
            if( null == _store ){ return;  }

            int count = 10;
            List<PageInfo> infos = null;

            while( !_shouldStop )
            {
                infos = DequeueSome( count );
                try{
                    _store.SaveContents( infos );
                }
                catch( Exception ex ){
                    _log.Enqueue( ex.ToString() );
                }
            }
        }
        / 队列方法
        private List<PageInfo> DequeueSome( int count )
        {
            List<PageInfo> infos = new List<PageInfo>();

            for( int i=0; i<count; i++ )  / 按每10条记录一组进行存储
            {
                infos.Add( _s_queue.Dequeue() );
            }

            return infos;
        }
      #endregion

      #region Private Members
        private EventLogger _log;    /日志

        private IStorage _store;                              /接口
        private static PageQueue _s_queue = new PageQueue();  /队列
        private List<Thread> _threads = new List<Thread>();   /线程

        private bool _shouldStop;
      #endregion
    }
  #endregion

  #region 日志线程类
    public class EventLogger : IThread
    {
        / 构造函数1
        public EventLogger(){}

        / 构造函数2
        public EventLogger( ILogger logger )
        {
            _logger = logger;
            _shouldStop = false;
            _selfCheckInterval = 300000;    / 5分钟
        }
      #region Public Properties
        public Queue<string> Queue
        {
            get{  return _s_queue;  }
        }
        public List<Thread> Threads
        {
            get{  return _threads;  }
        }
      #endregion

      #region 队列方法(Queue Method)
        public void Enqueue( string s )
        {
            lock( _s_queue ){
                _s_queue.Enqueue( s );
                Monitor.Pulse( _s_queue );
            }
        }
        public string Dequeue()
        {
            lock( _s_queue )
            {
                if( 1 > _s_queue.Count ){
                    Monitor.Wait( _s_queue );
                }
                return _s_queue.Dequeue();
            }
        }
      #endregion

      #region 线程方法(Thread Method)
        /
        public Thread AddThread()
        {
            Thread t = new Thread( new ThreadStart(ThreadRun) );
            t.IsBackground = true;
            t.Start();
            _threads.Add(t);
            return t;
        }
        / 减少线程
        public void RemoveThread()
        {
            / 尚未实现
        }
        / 请求线程暂停
        public void RequestThreadPause()
        {
            / 尚未实现
        }
        / 请求线程继续
        public void RequestThreadPause( bool pauseOrContinue )
        {
            / 尚未实现
        }
        / 请求线程停止
        public void RequestThreadStop()
        {
            _shouldStop = true;
        }
        / 增加自检线程
        public void AddSelfCheckThread()
        {
            if( false == _isSelfCheckRun ){
                Thread t = new Thread( new ThreadStart(SelfCheck) );
                t.IsBackground = true;
                t.Start();
                _isSelfCheckRun = true;
            }
        }
      #endregion

      #region Private Methods
        / 日志主线程函数
        private void ThreadRun()
        {
            if( null == _logger ){ return;  }

            while( !_shouldStop )
            {
                try{
                    _logger.Write( Dequeue() );
                }
                catch( Exception ex ){
                    Console.WriteLine( string.Format( "警告:日志写入发生错误{0}",ex.ToString() ) );
                }
            }
        }
        / 日志自检子线程函数
        private void SelfCheck()
        {
            if( null == _logger ){ return;  }

            while( !_shouldStop )
            {
                try{
                    _logger.Write( "日志自检完成" );
                    Thread.Sleep( _selfCheckInterval );
                }
                catch( Exception ex ){
                    Console.WriteLine( string.Format( "警告:日志自检发生错误{0}",ex.ToString() ) );
                }
            }
        }
      #endregion

      #region Private Members
        private ILogger _logger = null;                               / 接口
        private static Queue<string> _s_queue = new Queue<string>();  / 一些标志性事件(异常或成功)
        private List<Thread> _threads = new List<Thread>();           / 一个队列可以有多个线程

        private bool _shouldStop;

        private int _selfCheckInterval;   / 日志模块自检间隔
        private static bool _isSelfCheckRun = false;
      #endregion
    }
  #endregion

} / end namespace My.WSE

Android 图片转灰度

/** 
 * 图片转灰度 
 *  
 * @param bmSrc 
 * @return 
 */  
public static Bitmap bitmap2Gray(Bitmap bmSrc)  
{  
    int width, height;  
    height = bmSrc.getHeight();  
    width = bmSrc.getWidth();  
    Bitmap bmpGray = null;  
    bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
    Canvas c = new Canvas(bmpGray);  
    Paint paint = new Paint();  
    ColorMatrix cm = new ColorMatrix();  
    cm.setSaturation(0);  
    ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);  
    paint.setColorFilter(f);  
    c.drawBitmap(bmSrc, 0, 0, paint);  
  
    return bmpGray;  
}  
 
/**
* 图片转灰度
* 
* @param bmSrc
* @return
*/
public static Bitmap bitmap2Gray(Bitmap bmSrc)
{
int width, height;
height = bmSrc.getHeight();
width = bmSrc.getWidth();
Bitmap bmpGray = null;
bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGray);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmSrc, 0, 0, paint);
 
return bmpGray;
}

UIImage转为灰度图 ios

-(UIImage*)getGrayImage:(UIImage*)sourceImage 
{ 
    int width = sourceImage.size.width; 
    int height = sourceImage.size.height; 
   
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); 
    CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,kCGImageAlphaNone); 
    CGColorSpaceRelease(colorSpace); 
   
    if (context == NULL) { 
        return nil; 
    } 
   
    CGContextDrawImage(context,CGRectMake(0, 0, width, height), sourceImage.CGImage); 
    UIImage *grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)]; 
    CGContextRelease(context); 
   
    return grayImage; 
}

3525279752

用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升。但是css3动画还是有不少局限性,比如不是所有属性都能参与动画、动画缓动效果太少、无法完全控制动画过程等等。所以有的时候我们还是不得不使用setTimeout或setInterval的方式来实现动画,可是setTimeout和setInterval有着严重的性能问题,虽然某些现代浏览器对这两函个数进行了一些优化,但还是无法跟css3的动画性能相提并论。这个时候,就该requestAnimationFrame出马了。

requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API,目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,唯一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。

requestAnimationFrame 比起 setTimeout、setInterval的优势主要有两点:

1、requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。

2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。

像setTimeout、setInterval一样,requestAnimationFrame是一个全局函数。调用requestAnimationFrame后,它会要求浏览器根据自己的频率进行一次重绘,它接收一个回调函数作为参数,在即将开始的浏览器重绘时,会调用这个函数,并会给这个函数传入调用回调函数时的时间作为参数。由于requestAnimationFrame的功效只是一次性的,所以若想达到动画效果,则必须连续不断的调用requestAnimationFrame,就像我们使用setTimeout来实现动画所做的那样。requestAnimationFrame函数会返回一个资源标识符,可以把它作为参数传入cancelAnimationFrame函数来取消requestAnimationFrame的回调。怎么样,是不是也跟setTimeout的clearTimeout很相似啊。

所以,可以这么说,requestAnimationFrame就是一个性能优化版、专为动画量身打造的setTimeout,不同的是requestAnimationFrame不是自己指定回调函数运行的时间,而是跟着浏览器内建的刷新频率来执行回调,这当然就能达到浏览器所能实现动画的最佳效果了。

目前,各个支持requestAnimationFrame的浏览器有些还是自己的私有实现,所以必须加前缀,对于不支持requestAnimationFrame的浏览器,我们只能使用setTimeout,因为两者的使用方式几近相同,所以这两者的兼容并不难。对于支持requestAnimationFrame的浏览器,我们使用requestAnimationFrame,而不支持的我们优雅降级使用传统的setTimeout。把它们封装一下,就能得到一个统一兼容各大浏览器的API了。

代码可以到这里来查看:/gist.github.com/chaping/88813f56e75b0fd43f8c

var lastTime = 0;
var prefixes = 'webkit moz ms o'.split(' '); /各浏览器前缀

var requestAnimationFrame = window.requestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame;

var prefix;
/通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
for( var i = 0; i < prefixes.length; i++ ) {
    if ( requestAnimationFrame && cancelAnimationFrame ) {
      break;
    }
    prefix = prefixes[i];
    requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
    cancelAnimationFrame  = cancelAnimationFrame  || window[ prefix + 'CancelAnimationFrame' ] || window[ prefix + 'CancelRequestAnimationFrame' ];
}

/如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
if ( !requestAnimationFrame || !cancelAnimationFrame ) {
    requestAnimationFrame = function( callback, element ) {
      var currTime = new Date().getTime();
      /为了使setTimteout的尽可能的接近每秒60帧的效果
      var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); 
      var id = window.setTimeout( function() {
        callback( currTime + timeToCall );
      }, timeToCall );
      lastTime = currTime + timeToCall;
      return id;
    };
    
    cancelAnimationFrame = function( id ) {
      window.clearTimeout( id );
    };
}
/得到兼容各浏览器的API
window.requestAnimationFrame = requestAnimationFrame; 
window.cancelAnimationFrame = cancelAnimationFrame;

这样子我们就能在所有浏览器上使用requestAnimationFrame和cancelAnimationFrame了。

下面举个简单的例子来说明怎么运用requestAnimationFrame进行动画,下面的代码会将id为demo的div以动画的形式向右移动到300px

<div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div>

<script>
var demo = document.getElementById('demo');
function rander(){
    demo.style.left = parseInt(demo.style.left) + 1 + 'px'; /每一帧向右移动1px
}
requestAnimationFrame(function(){
    rander();
    /当超过300px后才停止
    if(parseInt(demo.style.left)<=300) requestAnimationFrame(arguments.callee);
});
</script>