X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F01_core%2F14_XTimer.js;h=48b27a3124d63ac2be4def15e1bb6ff2b6471be3;hb=d836e6243878426d4cfd7a14ceb9b77db9f92b57;hp=07250371aa546d842beee008b8925f11864284f9;hpb=5f61a48d303bf9ca6bf021d8957aac743fc8958b;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/01_core/14_XTimer.js b/0.6.x/js/01_core/14_XTimer.js index 0725037..48b27a3 100644 --- a/0.6.x/js/01_core/14_XTimer.js +++ b/0.6.x/js/01_core/14_XTimer.js @@ -1,4 +1,4 @@ -/** +/* * use X.Callback */ @@ -34,9 +34,21 @@ // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // -var X_Timer_SET_TIMEOUT = window.setTimeout, +var + + /** + * ç¾å¨æã® ms ãè¿ãã¾ãã new Date().getTime() ã®å¤ã§ãã + * @alias X.Timer.now + * @function + * @return {number} ããªç§ + */ + X_Timer_now = Date.now || ( function(){ return +new Date; } ), + + X_Timer_SET_TIMEOUT = window.setTimeout, X_Timer_CLEAR_TIMEOUT = window.clearTimeout, - + + // http://uupaa.hatenablog.com/entry/2012/02/01/083607 + // Firefox 4 partial (request only), Mobile Firefox5 ready (request only), Firefox 11 ready (cancel impl) X_Timer_REQ_ANIME_FRAME = window.requestAnimationFrame || window.webkitRequestAnimationFrame || @@ -44,6 +56,7 @@ var X_Timer_SET_TIMEOUT = window.setTimeout, window.oRequestAnimationFrame || window.msRequestAnimationFrame || false, + X_Timer_CANCEL_ANIME_FRAME = window.cancelRequestAnimationFrame || window.webkitCancelAnimationFrame || @@ -56,96 +69,64 @@ var X_Timer_SET_TIMEOUT = window.setTimeout, X_Timer_INTERVAL_TIME = 16, X_Timer_TICKET_LIST = [], X_Timer_removal = null, + X_Timer_skipUpdate = false, X_Timer_uid = 0, X_Timer_timerId = 0, - X_Timer_next = 0, - X_Timer_busyTimeout = false, - X_Timer_endTime = 0, // iOS + X_Timer_busyTimeout = false, + X_Timer_timeStamp = 0, // setTimeout ã«ç»é²ããæé + X_Timer_waitTime = 0, // å¾ ã¡æé + X_Timer_currentUID = 0, // ç¾å¨çºç«ä¸ã® uid X_Timer_REQ_FRAME_LIST = [], X_Timer_requestID = 0, - X_Timer_busyOnFrame = false; + X_Timer_busyOnFrame = false, -// ------------------------------------------------------------------------- // -// --- interface ----------------------------------------------------------- // -// ------------------------------------------------------------------------- // -X.Timer = { - - add : function( time, opt_count, args1, args2, args3 ){ - var list = X_Timer_TICKET_LIST, - hash, obj; - time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // æ£ã®æ°ã§ä½¿ãããMath.floor(x)ããã(x | 0)ãã«; - - if( !X.Type.isNumber( opt_count ) ){ - args3 = args2; - args2 = args1; - args1 = opt_count; - opt_count = 0; - }; - - hash = X_Callback_classifyCallbackArgs( args1, args2, args3 ); - if( !hash ) return -1; // dev only - - if( !hash.k ) hash = { f : hash }; - hash.time = time; - hash.last = time; - hash.count = opt_count; - hash.uid = ++X_Timer_uid; - list[ list.length ] = hash; - - !X_Timer_busyTimeout && X_Timer_update(); - return X_Timer_uid; - }, - - once : function( time, args1, args2, args3 ){ - return X.Timer.add( time, 1, args1, args2, args3 ); - }, - - remove : function( uid ){ - var list = X_Timer_TICKET_LIST, - i = list.length, - l = i, - f, q; - // fire ä¸ã® cancel - if( X_Timer_busyTimeout ){ - if( !X_Timer_removal ) X_Timer_removal = {}; - X_Timer_removal[ uid ] = true; - } else { - for( ; i; ){ - - if( ( q = list[ --i ] ).uid === uid ){ - list.splice( i, 1 ); - ( /* q[ INDEX_COUNT ] <= next || */ l === 1 ) && X_Timer_update(); - break; - }; - }; - }; - }, - - requestFrame : X_Timer_REQ_ANIME_FRAME ? + /** + * requestAnimationFrame ãã»ãããã¾ãã + * @alias X.Timer.requestFrame + * @function + * @param {*} args1 ã³ã¼ã«ããã¯ã®ããã®æ大㧠3 ã¤ã®å¼æ°ãæå®ãã¾ããåè:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} ã¿ã¤ãã¼IDã1 以ä¸ã®æ°å¤ãã¿ã¤ãã¼ã®è§£é¤ã«ä½¿ç¨ã + */ + X_Timer_requestFrame = X_Timer_REQ_ANIME_FRAME ? (function( args1, args2, args3 ){ var i = X_Timer_REQ_FRAME_LIST.length, f; i === 0 && ( X_Timer_requestID = X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) ); - f = X_Timer_REQ_FRAME_LIST[ i ] = X_Callback_classifyCallbackArgs( args1, args2, args3 ); + f = X_Callback_classifyCallbackArgs( args1, args2, args3 ); + if( !f.kind ) f = { func : f }; + X_Timer_REQ_FRAME_LIST[ i ] = f; return f.uid = ++X_Timer_uid; }) : (function( args1, args2, args3 ){ var i = X_Timer_REQ_FRAME_LIST.length, f; - i === 0 && ( X_Timer_requestID = X.Timer.add( 0, 1, X_Timer_onEnterFrame ) ); - f = X_Timer_REQ_FRAME_LIST[ i ] = X_Callback_classifyCallbackArgs( args1, args2, args3 ); + i === 0 && ( X_Timer_requestID = X_Timer_add( 0, 1, X_Timer_onEnterFrame ) ); + f = X_Callback_classifyCallbackArgs( args1, args2, args3 ); + if( !f.kind ) f = { func : f }; + X_Timer_REQ_FRAME_LIST[ i ] = f; return f.uid = ++X_Timer_uid; }), - - cancelFrame : X_Timer_CANCEL_ANIME_FRAME ? + + /** + * requestAnimationFrame ã解é¤ãã¾ããç»é²æã«åãåã£ãã¿ã¤ãã¼IDã使ç¨ãã¾ãã + * @alias X.Timer.cancelFrame + * @function + * @param {number|string} ã¿ã¤ãã¼ID, æ°åæåã®å ´åãããï¼ + * @return {number} 0 ãè¿ã + * @example if( timerID ) timerID = X.Timer.cancelFrame( timerID ); + */ + X_Timer_cancelFrame = X_Timer_CANCEL_ANIME_FRAME ? (function( uid ){ var list = X_Timer_REQ_FRAME_LIST, l = list.length, i = l, f; - // fire ä¸ã® cancel + if( X_Timer_busyOnFrame ){ + // fire ä¸ã® cancel if( !X_Timer_removal ) X_Timer_removal = {}; X_Timer_removal[ uid ] = true; } else { @@ -153,19 +134,22 @@ X.Timer = { if( ( f = list[ --i ] ).uid < uid ) break; if( f.uid === uid ){ list.splice( i, 1 ); - l === 1 && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID ); + // gecko ã§ã¯ cancelRequestAnimationFrame ãç¡ãå ´åããã + l === 1 && X_Timer_CANCEL_ANIME_FRAME && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID ); break; }; }; }; + return 0; }) : (function( uid ){ var list = X_Timer_REQ_FRAME_LIST, l = list.length, i = l, f; - // fire ä¸ã® cancel + if( X_Timer_busyOnFrame ){ + // fire ä¸ã® cancel if( !X_Timer_removal ) X_Timer_removal = {}; X_Timer_removal[ uid ] = true; } else { @@ -173,12 +157,43 @@ X.Timer = { if( ( f = list[ --i ] ).uid < uid ) break; if( f.uid === uid ){ list.splice( i, 1 ); - l === 1 && X.Timer.remove( X_Timer_requestID ); + l === 1 && X_Timer_remove( X_Timer_requestID ); break; }; }; }; - }) + return 0; + }); + + +// ------------------------------------------------------------------------- // +// --- interface ----------------------------------------------------------- // +// ------------------------------------------------------------------------- // + +/** + *
setTimeout ãã©ãããã¾ããè¤æ°ã®ã¿ã¤ãã¼ãç»é²ãã¦ã Web ãã©ã¦ã¶ã«ã¯ã²ã¨ã¤ã®ã¿ã¤ãã¼ãç»é²ãã¾ãã + *
åè:è¤éã§éããªã£ã JavaScript ãè¶ é«éåããæ¹æ³ï¼, + * [JavaScript]setIntervalãå®é¨ãã + *
æå®æéã®çµéããã¿ã¤ãã¼ã¯ãããéå»ã®ãã®ããé çªã«ã³ã¼ã«ããã¯ããã¾ãã + *
setTimeout ã®ã³ã¼ã«ããã¯ã«æååããæå®ã§ããªããã©ã¦ã¶ããã対çãã¦ãã¾ãã + *
requestAnimationFrame ãã©ãããã¾ãããã³ãã¼ãã¬ãã£ãã¯ã¹ä»ã® requestAnimationFrame ããªãå ´åãsetTimeout ã«ãã©ã¼ã«ããã¯ãã¾ãã + * + * @namespace X.Timer + * @alias X.Timer + */ +X[ 'Timer' ] = { + + 'now' : X_Timer_now, + + 'add' : X_Timer_add, + + 'once' : X_Timer_once, + + 'remove' : X_Timer_remove, + + 'requestFrame' : X_Timer_requestFrame, + + 'cancelFrame' : X_Timer_cancelFrame }; @@ -186,47 +201,139 @@ X.Timer = { // --- implements ---------------------------------------------------------- // // ------------------------------------------------------------------------- // -if( X.UA.IE4 || X.UA.MacIE ){ + /** + * ã¿ã¤ãã¼ãã»ãããã¾ãã + * @alias X.Timer.add + * @param {number} time ããªç§ + * @param {number} opt_count åæ°ãçç¥å¯è½ãæå®åæ°ã§èªåã§ã¿ã¤ãã¼ãç ´æ£ãã¾ãã0 ãæå®ããå ´åç¡éã«ã¿ã¤ãã¼ãå¼ã°ãã¾ããçç¥ããå ´å 0 ã¨åãã§ãã + * @param {*} args1 ã³ã¼ã«ããã¯ã®ããã®æ大㧠3 ã¤ã®å¼æ°ãæå®ãã¾ããåè:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} ã¿ã¤ãã¼IDã1 以ä¸ã®æ°å¤ãã¿ã¤ãã¼ã®è§£é¤ã«ä½¿ç¨ã + * @example timerID = X.Timer.add( 1000, 5, thisContext, onTimer ); + */ + function X_Timer_add( time, opt_count, args1, args2, args3 ){ + var list = X_Timer_TICKET_LIST, + hash, obj; + time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // æ£ã®æ°ã§ä½¿ãããMath.floor(x)ããã(x | 0)ãã«; + + if( !X_Type_isNumber( opt_count ) ){ + args3 = args2; + args2 = args1; + args1 = opt_count; + opt_count = 0; + }; + + hash = X_Callback_classifyCallbackArgs( args1, args2, args3 ); + if( !hash ) return -1; // dev only + + if( !hash.kind ) hash = { func : hash }; + hash.time = time; + hash.last = time; + hash.count = opt_count; + hash.uid = ++X_Timer_uid; + list[ list.length ] = hash; + + !X_Timer_busyTimeout && X_Timer_update(); + return X_Timer_uid; + }; + + /** + * 1 åå¼ã°ããã解é¤ãããã¿ã¤ãã¼ãã»ãããã¾ãã + * @alias X.Timer.once + * @param {number} time ããªç§ + * @param {*} args1 ã³ã¼ã«ããã¯ã®ããã®æ大㧠3 ã¤ã®å¼æ°ãæå®ãã¾ããåè:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} ã¿ã¤ãã¼IDã1 以ä¸ã®æ°å¤ãã¿ã¤ãã¼ã®è§£é¤ã«ä½¿ç¨ã + */ + function X_Timer_once( time, args1, args2, args3 ){ + return X_Timer_add( time, 1, args1, args2, args3 ); + }; + + /** + * ã¿ã¤ãã¼ã解é¤ãã¾ããç»é²æã«åãåã£ãã¿ã¤ãã¼IDã使ç¨ãã¾ãã + * @alias X.Timer.remove + * @param {number} ã¿ã¤ãã¼ID + * @return {number} 0 ãè¿ã + * @example if( timerID ) timerID = X.Timer.remove( timerID ); + */ + function X_Timer_remove( uid ){ + var list = X_Timer_TICKET_LIST, + i = list.length, + l = i, + f, q, eventDispatcher, lazy, listeners; + + if( X_Timer_busyTimeout ){ + // fire ä¸ã® cancel + if( !X_Timer_removal ) X_Timer_removal = {}; + X_Timer_removal[ uid ] = true; + } else { + for( ; i; ){ + if( ( q = list[ --i ] ).uid === uid ){ + list.splice( i, 1 ); + + /* + * lazyDispatch ä¸ã® EventDispatcher ã®æç¡ã調ã¹ã + */ + if( X_EventDispatcher_LAZY_TIMERS[ uid ] ){ + delete X_EventDispatcher_LAZY_TIMERS[ uid ]; + }; + + !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update(); + break; + }; + }; + }; + return 0; + }; + +if( X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ){ X.Timer[ '_' ] = X_Timer_onTimeout; X_Timer_onTimeout = 'X.Timer._()'; }; function X_Timer_onTimeout(){ - var next = X_Timer_next, + var now = X_Timer_now(), + minus = ( ( now - X_Timer_timeStamp ) / X_Timer_INTERVAL_TIME | 0 ) || 1, list = X_Timer_TICKET_LIST, i = 0, l = list.length, - limit = X.getTime() + X_Timer_INTERVAL_TIME / 2, + limit = now + X_Timer_INTERVAL_TIME / 2, heavy, q, f, c, r, uid; + //console.log( 'äºå®æéã¨çºç«æéã®å·®:' + ( now - X_Timer_timeStamp - X_Timer_waitTime * X_Timer_INTERVAL_TIME ) + ' -:' + minus + ' next:' + X_Timer_waitTime ); + if( X_Timer_busyTimeout ){ - alert( 'busy!' ); + alert( 'X_Timer_busyTimeout ãã©ã°ãç«ã£ãã¾ã¾!ã¨ã©ã¼ã®å¯è½æ§' ); }; X_Timer_busyTimeout = true; for( ; i < l; ++i ){ q = list[ i ]; - if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue; - if( 0 < ( q.last -= next ) ) continue; - if( heavy ){ - if( q.last <= 0 ) q.last = 1; + if( + ( X_Timer_removal && X_Timer_removal[ q.uid ] ) || // timerId 㯠remove ç»é²ããã¦ãã + 0 < ( q.last -= minus ) || // æéãçµéãã¦ããªã + heavy && ( q.last = 1 ) // æéã¯çµéããããããã¼ãã©ã°ãç«ã£ã¦ãã + ){ continue; }; c = q.count; - if( q.k ){ - //q.a = []; + X_Timer_currentUID = q.uid; + + if( q.kind ){ r = X_Callback_proxyCallback( q, [] ); } else { - r = q.f(); + r = q.func(); }; //console.log( 'fire....' ); - if( limit <= X.getTime() ){ - console.log( '******* heavy!' ); + if( limit <= X_Timer_now() ){ + //console.log( '******* heavy!' ); // é¢æ°ã®å®è¡ã«æéããããå ´åã次ã®ã¿ã¤ãã³ã°ã« heavy = true; }; @@ -240,12 +347,16 @@ function X_Timer_onTimeout(){ if( 1 < c ) --q.count; q.last = q.time; }; - X_Timer_timerId = 0; + X_Timer_timerId = X_Timer_currentUID = 0; X_Timer_busyTimeout = false; + if( X_Timer_removal ){ + X_Timer_skipUpdate = true; for( uid in X_Timer_removal ){ - X.Timer.remove( X_Timer_removal[ uid ] ); + //if( X_EMPTY_OBJECT[ uid ] ) continue; + X_Timer_remove( uid ); }; + X_Timer_skipUpdate = false; X_Timer_removal = null; }; X_Timer_update(); @@ -265,23 +376,36 @@ function X_Timer_update(){ n = list[ i - 1 ].last; - if( n < X_Timer_next || X_Timer_timerId === 0 ){ - X_Timer_timerId && X_Timer_CLEAR_TIMEOUT( X_Timer_timerId ); - X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, X_Timer_INTERVAL_TIME * n ); - X_Timer_endTime = X.getTime() + X_Timer_INTERVAL_TIME * n; // iOS - X_Timer_next = n; + if( n < X_Timer_waitTime || X_Timer_timerId === 0 ){ + if( X_Timer_timerId ){ + X_Timer_CLEAR_TIMEOUT( X_Timer_timerId ); + n -= ( X_Timer_now() - X_Timer_timeStamp ) / X_Timer_INTERVAL_TIME | 0; + 0 <= n || ( n = 0 ); // è² ã®æ°ã¯ 0 ã« + }; + X_Timer_timeStamp = X_Timer_now(); + X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, X_Timer_INTERVAL_TIME * n ); + X_Timer_waitTime = n; }; }; +// 大ãã -> å°ãã +function X_Timer_compareQueue( a, b ){ + return a.last < b.last ? 1 : a.last === b.last ? 0 : -1; +}; + // http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html // iOS6 ã¹ã¯ãã¼ã«ä¸ã®ã¿ã¤ãã¼çºç«çµ¡ã¿ã®ãã°åå¿ -if( X.UA.iOS ){ +if( X_UA[ 'iOS' ] ){ window.addEventListener( 'scroll', function(){ - var last; + var last, now; if( X_Timer_timerId ){ - window.clearTimeout( X_Timer_timerId ); - last = X_Timer_endTime - X.getTime(); - X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 ); + X_Timer_CLEAR_TIMEOUT( X_Timer_timerId ); + now = X_Timer_now(); + last = X_Timer_timeStamp + X_Timer_INTERVAL_TIME * X_Timer_waitTime - now; + X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 ); + // æ´æ° + X_Timer_timeStamp = now; + X_Timer_waitTime = last / X_Timer_INTERVAL_TIME | 0; }; }); }; @@ -293,39 +417,34 @@ function X_Timer_onEnterFrame( time ){ l = list.length, i = 0, q, uid, args; - time = time || X.getTime(); + time = time || X_Timer_now(); X_Timer_busyOnFrame = true; - // console.log( X.getTime() + ' , ' + time ); + // console.log( X_Timer_now() + ' , ' + time ); for( ; i < l; ++i ){ q = list[ i ]; if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue; - if( q.k ){ + if( q.kind ){ X_Callback_proxyCallback( q, args || ( args = [ time ] ) ); } else { - q( time ); + q.func( time ); }; }; list.splice( 0, l ); if( list.length ){ - X_Timer_requestID = X_Timer_REQ_ANIME_FRAME ? X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) : X.Timer.add( 0, 1, X_Timer_onEnterFrame ); + X_Timer_requestID = X_Timer_REQ_ANIME_FRAME ? X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) : X_Timer_add( 0, 1, X_Timer_onEnterFrame ); }; X_Timer_busyOnFrame = false; if( X_Timer_removal ){ for( uid in X_Timer_removal ){ - X.Timer.cancelFrame( X_Timer_removal[ uid ] ); + //if( X_EMPTY_OBJECT[ uid ] ) continue; + X_Timer_cancelFrame( X_Timer_removal[ uid ] ); }; X_Timer_removal = null; }; }; -// 大ãã -> å°ãã -function X_Timer_compareQueue( a, b ){ - return a.last < b.last ? 1 : a.last === b.last ? 0 : -1; -}; - - console.log( 'X.Core.Timer' );