* use X.Callback\r
*/\r
\r
-var _enterFrame =\r
- window.requestAnimationFrame ||\r
- window.webkitRequestAnimationFrame ||\r
- window.mozRequestAnimationFrame ||\r
- window.oRequestAnimationFrame ||\r
- window.msRequestAnimationFrame ||\r
- false,\r
- _cancelFrame =\r
- window.cancelRequestAnimationFrame ||\r
- window.webkitCancelAnimationFrame ||\r
- window.webkitCancelRequestAnimationFrame ||\r
- window.mozCancelRequestAnimationFrame ||\r
- window.oCancelRequestAnimationFrame ||\r
- window.msCancelRequestAnimationFrame ||\r
- false;\r
-\r
/*\r
* \r
* http://please-sleep.cou929.nu/script-yielding-with-setimmediate.html\r
}\r
*/\r
\r
-X.Timer = {\r
- INTERVAL_TIME : 16,\r
- TICKET_LIST : [],\r
- uid : 0,\r
- timerId : 0,\r
- endTime : 0, // iOS\r
- next : 0,\r
- busy : false, // for Opera7\r
- \r
- REQ_FRAME_LIST : [],\r
- requestID : 0,\r
+\r
+// ------------------------------------------------------------------------- //\r
+// ------------ local variables -------------------------------------------- //\r
+// ------------------------------------------------------------------------- //\r
+\r
+var X_Timer_SET_TIMEOUT = window.setTimeout,\r
+ X_Timer_CLEAR_TIMEOUT = window.clearTimeout,\r
\r
- _loop : function(){\r
- var next = X.Timer.next,\r
- list = X.Timer.TICKET_LIST,\r
- i = 0,\r
- l = list.length,\r
- limit = X.getTime() + X.Timer.INTERVAL_TIME / 2,\r
- heavy,\r
- q, f, c, r;\r
- \r
- if( X.Timer.busy ){\r
- alert( 'busy!' );\r
- };\r
- \r
- X.Timer.busy = true;\r
- \r
- for( ; i < l; ++i ){\r
- q = list[ i ];\r
- if( 0 < ( q.last -= next ) ) continue;\r
- if( heavy ){\r
- if( q.last <= 0 ) q.last = 1;\r
- continue;\r
- };\r
- c = q.count;\r
- \r
- if( q.k ){\r
- q.a = [];\r
- r = X.Callback._proxyCallback( q );\r
- } else {\r
- r = q.f();\r
- };\r
- \r
- console.log( 'fire....' );\r
- \r
- if( limit <= X.getTime() ){\r
- console.log( 'heavy' );\r
- // 関数の実行に時間が係る場合、次のタイミングに\r
- heavy = true;\r
- }; \r
- \r
- if( r & X.Callback.UN_LISTEN || c === 1 ){\r
- list.splice( i, 1 );\r
- --i;\r
- --l;\r
- continue;\r
- } else\r
- if( 1 < c ) --q.count;\r
- q.last = q.time;\r
- };\r
- X.Timer.timerId = 0;\r
- X.Timer.busy = false;\r
- X.Timer._update();\r
- },\r
- _update : function(){\r
- var list = X.Timer.TICKET_LIST,\r
- i = list.length,\r
- n;\r
- if( i === 0 ){\r
- X.Timer.timerId && window.clearTimeout( X.Timer.timerId );\r
- X.Timer.timerId = 0;\r
- return;\r
- };\r
- \r
- 1 < i && list.sort( x_timer_compareQueue );\r
+ X_Timer_REQ_ANIME_FRAME =\r
+ window.requestAnimationFrame ||\r
+ window.webkitRequestAnimationFrame ||\r
+ window.mozRequestAnimationFrame ||\r
+ window.oRequestAnimationFrame ||\r
+ window.msRequestAnimationFrame ||\r
+ false,\r
+ X_Timer_CANCEL_ANIME_FRAME =\r
+ window.cancelRequestAnimationFrame ||\r
+ window.webkitCancelAnimationFrame ||\r
+ window.webkitCancelRequestAnimationFrame ||\r
+ window.mozCancelRequestAnimationFrame ||\r
+ window.oCancelRequestAnimationFrame ||\r
+ window.msCancelRequestAnimationFrame ||\r
+ false,\r
\r
- n = list[ i - 1 ].last;\r
- \r
- if( n < X.Timer.next || X.Timer.timerId === 0 ){\r
- X.Timer.timerId && window.clearTimeout( X.Timer.timerId );\r
- X.Timer.timerId = window.setTimeout( X.Timer._loop, X.Timer.INTERVAL_TIME * n );\r
- X.Timer.endTime = X.getTime() + X.Timer.INTERVAL_TIME * n; // iOS\r
- X.Timer.next = n;\r
- };\r
- },\r
+ X_Timer_INTERVAL_TIME = 16,\r
+ X_Timer_TICKET_LIST = [],\r
+ X_Timer_removal = null,\r
+ X_Timer_uid = 0,\r
+ X_Timer_timerId = 0,\r
+ X_Timer_next = 0,\r
+ X_Timer_busyTimeout = false, \r
+ X_Timer_endTime = 0, // iOS\r
\r
- // ページを読み込んでからの時間\r
- _onEnterFrame : function ( time ){\r
- var list = X.Timer.REQ_FRAME_LIST,\r
- l = list.length,\r
- i = 0, q;\r
+ X_Timer_REQ_FRAME_LIST = [],\r
+ X_Timer_requestID = 0,\r
+ X_Timer_busyOnFrame = false;\r
\r
- time = time || X.getTime();\r
- // console.log( X.getTime() + ' , ' + time );\r
- for( ; i < l; ++i ){\r
- q = list[ i ];\r
- \r
- if( q.k ){\r
- q.a = [ time ];\r
- X.Callback._proxyCallback( q );\r
- } else {\r
- q( time );\r
- };\r
- };\r
-\r
- list.splice( 0, l );\r
- if( list.length ){\r
- X.Timer.requestID = _enterFrame ? _enterFrame( X.Timer._onEnterFrame ) : X.Timer.add( 0, 1, X.Timer._onEnterFrame );\r
- };\r
- },\r
+// ------------------------------------------------------------------------- //\r
+// --- interface ----------------------------------------------------------- //\r
+// ------------------------------------------------------------------------- //\r
+X.Timer = {\r
\r
add : function( time, opt_count, args1, args2, args3 ){\r
- var list = X.Timer.TICKET_LIST,\r
+ var list = X_Timer_TICKET_LIST,\r
hash, obj;\r
- time = time < X.Timer.INTERVAL_TIME ? 1 : time / X.Timer.INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;\r
+ time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;\r
\r
if( !X.Type.isNumber( opt_count ) ){\r
args3 = args2;\r
hash.time = time;\r
hash.last = time;\r
hash.count = opt_count;\r
- hash.uid = ++X.Timer.uid;\r
+ hash.uid = ++X_Timer_uid;\r
list[ list.length ] = hash;\r
\r
- !X.Timer.busy && X.Timer._update();\r
- return X.Timer.uid;\r
+ !X_Timer_busyTimeout && X_Timer_update();\r
+ return X_Timer_uid;\r
},\r
+ \r
once : function( time, args1, args2, args3 ){\r
return X.Timer.add( time, 1, args1, args2, args3 );\r
},\r
+ \r
remove : function( uid ){\r
- var list = X.Timer.TICKET_LIST,\r
+ var list = X_Timer_TICKET_LIST,\r
i = list.length,\r
l = i,\r
f, q;\r
- for( ; i; ){\r
- // TODO\r
- // fire 中の cancel\r
- if( ( q = list[ --i ] ).uid === uid ){\r
- list.splice( i, 1 );\r
- !X.Timer.busy && ( /* q[ INDEX_COUNT ] <= next || */ l === 1 ) && X.Timer._update();\r
- break;\r
- };\r
+ // fire 中の cancel\r
+ if( X_Timer_busyTimeout ){\r
+ if( !X_Timer_removal ) X_Timer_removal = {};\r
+ X_Timer_removal[ uid ] = true;\r
+ } else {\r
+ for( ; i; ){\r
+ \r
+ if( ( q = list[ --i ] ).uid === uid ){\r
+ list.splice( i, 1 );\r
+ ( /* q[ INDEX_COUNT ] <= next || */ l === 1 ) && X_Timer_update();\r
+ break;\r
+ };\r
+ }; \r
};\r
},\r
\r
- requestFrame : _enterFrame ?\r
+ requestFrame : X_Timer_REQ_ANIME_FRAME ?\r
(function( args1, args2, args3 ){\r
- var i = X.Timer.REQ_FRAME_LIST.length,\r
+ var i = X_Timer_REQ_FRAME_LIST.length,\r
f;\r
- i === 0 && ( X.Timer.requestID = _enterFrame( X.Timer._onEnterFrame ) );\r
- f = X.Timer.REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
- return f.uid = ++X.Timer.uid;\r
+ i === 0 && ( X_Timer_requestID = X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) );\r
+ f = X_Timer_REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
+ return f.uid = ++X_Timer_uid;\r
}) :\r
(function( args1, args2, args3 ){\r
- var i = X.Timer.REQ_FRAME_LIST.length,\r
+ var i = X_Timer_REQ_FRAME_LIST.length,\r
f;\r
- i === 0 && ( X.Timer.requestID = X.Timer.add( 0, 1, X.Timer._onEnterFrame ) );\r
- f = X.Timer.REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
- return f.uid = ++X.Timer.uid;\r
+ i === 0 && ( X_Timer_requestID = X.Timer.add( 0, 1, X_Timer_onEnterFrame ) );\r
+ f = X_Timer_REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );\r
+ return f.uid = ++X_Timer_uid;\r
}),\r
\r
- cancelFrame : _cancelFrame ?\r
+ cancelFrame : X_Timer_CANCEL_ANIME_FRAME ?\r
(function( uid ){\r
- var list = X.Timer.REQ_FRAME_LIST,\r
+ var list = X_Timer_REQ_FRAME_LIST,\r
l = list.length,\r
i = l,\r
f;\r
- for( ; i; ){\r
- if( ( f = list[ --i ] ).uid < uid ) break;\r
- if( f.uid === uid ){\r
- // TODO\r
- // fire 中の cancel\r
- list.splice( i, 1 );\r
- l === 1 && _cancelFrame( X.Timer.requestID );\r
- break;\r
- };\r
+ // fire 中の cancel\r
+ if( X_Timer_busyOnFrame ){\r
+ if( !X_Timer_removal ) X_Timer_removal = {};\r
+ X_Timer_removal[ uid ] = true;\r
+ } else {\r
+ for( ; i; ){\r
+ if( ( f = list[ --i ] ).uid < uid ) break;\r
+ if( f.uid === uid ){\r
+ list.splice( i, 1 );\r
+ l === 1 && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
+ break;\r
+ };\r
+ }; \r
};\r
}) :\r
(function( uid ){\r
- var list = X.Timer.REQ_FRAME_LIST,\r
+ var list = X_Timer_REQ_FRAME_LIST,\r
l = list.length,\r
i = l,\r
f;\r
- for( ; i; ){\r
- if( ( f = list[ --i ] ).uid < uid ) break;\r
- if( f.uid === uid ){\r
- list.splice( i, 1 );\r
- l === 1 && X.Timer.remove( X.Timer.requestID );\r
- break;\r
+ // fire 中の cancel\r
+ if( X_Timer_busyOnFrame ){\r
+ if( !X_Timer_removal ) X_Timer_removal = {};\r
+ X_Timer_removal[ uid ] = true;\r
+ } else {\r
+ for( ; i; ){\r
+ if( ( f = list[ --i ] ).uid < uid ) break;\r
+ if( f.uid === uid ){\r
+ list.splice( i, 1 );\r
+ l === 1 && X.Timer.remove( X_Timer_requestID );\r
+ break;\r
+ };\r
};\r
};\r
})\r
\r
};\r
\r
-// 大きい -> 小さい\r
-function x_timer_compareQueue( a, b ){\r
- return a.last < b.last ? 1 : a.last === b.last ? 0 : -1;\r
+// ------------------------------------------------------------------------- //\r
+// --- implements ---------------------------------------------------------- //\r
+// ------------------------------------------------------------------------- //\r
+\r
+if( X.UA.IE < 5 || X.UA.MacIE ){\r
+ X.Timer[ '_' ] = X_Timer_onTimeout;\r
+ X_Timer_onTimeout = 'X.Timer._()';\r
+};\r
+\r
+function X_Timer_onTimeout(){\r
+ var next = X_Timer_next,\r
+ list = X_Timer_TICKET_LIST,\r
+ i = 0,\r
+ l = list.length,\r
+ limit = X.getTime() + X_Timer_INTERVAL_TIME / 2,\r
+ heavy,\r
+ q, f, c, r, uid;\r
+ \r
+ if( X_Timer_busyTimeout ){\r
+ alert( 'busy!' );\r
+ };\r
+ \r
+ X_Timer_busyTimeout = true;\r
+ \r
+ for( ; i < l; ++i ){\r
+ q = list[ i ];\r
+ if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue;\r
+ if( 0 < ( q.last -= next ) ) continue;\r
+ if( heavy ){\r
+ if( q.last <= 0 ) q.last = 1;\r
+ continue;\r
+ };\r
+ c = q.count;\r
+ \r
+ if( q.k ){\r
+ q.a = [];\r
+ r = X.Callback._proxyCallback( q );\r
+ } else {\r
+ r = q.f();\r
+ };\r
+ \r
+ //console.log( 'fire....' );\r
+ \r
+ if( limit <= X.getTime() ){\r
+ console.log( '******* heavy!' );\r
+ // 関数の実行に時間がかかる場合、次のタイミングに\r
+ heavy = true;\r
+ };\r
+ \r
+ if( r & X.Callback.UN_LISTEN || c === 1 ){\r
+ list.splice( i, 1 );\r
+ --i;\r
+ --l;\r
+ continue;\r
+ } else\r
+ if( 1 < c ) --q.count;\r
+ q.last = q.time;\r
+ };\r
+ X_Timer_timerId = 0;\r
+ X_Timer_busyTimeout = false;\r
+ if( X_Timer_removal ){\r
+ for( uid in X_Timer_removal ){\r
+ X.Timer.remove( X_Timer_removal[ uid ] );\r
+ };\r
+ X_Timer_removal = null;\r
+ };\r
+ X_Timer_update();\r
};\r
\r
+function X_Timer_update(){\r
+ var list = X_Timer_TICKET_LIST,\r
+ i = list.length,\r
+ n;\r
+ if( i === 0 ){\r
+ X_Timer_timerId && X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );\r
+ X_Timer_timerId = 0;\r
+ return;\r
+ };\r
+ \r
+ 1 < i && list.sort( X_Timer_compareQueue );\r
+ \r
+ n = list[ i - 1 ].last;\r
+ \r
+ if( n < X_Timer_next || X_Timer_timerId === 0 ){\r
+ X_Timer_timerId && X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );\r
+ X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, X_Timer_INTERVAL_TIME * n );\r
+ X_Timer_endTime = X.getTime() + X_Timer_INTERVAL_TIME * n; // iOS\r
+ X_Timer_next = n;\r
+ };\r
+};\r
\r
// http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html\r
// iOS6 スクロール中のタイマー発火絡みのバグ備忘\r
if( X.UA.iOS ){\r
window.addEventListener( 'scroll', function(){\r
- if( X.Timer.timerId ){\r
- window.clearTimeout( X.Timer.timerId );\r
- X.Timer.timerId = window.setTimeout( X.Timer._loop, Math.max( 0, X.Timer.endTime - X.getTime() ) );\r
+ var last;\r
+ if( X_Timer_timerId ){\r
+ window.clearTimeout( X_Timer_timerId );\r
+ last = X_Timer_endTime - X.getTime();\r
+ X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 );\r
};\r
});\r
};\r
\r
-if( X.UA.IE < 5 || X.UA.MacIE ){\r
- X.Timer[ '_ie_loop' ] = X.Timer._loop;\r
- X.Timer._loop = 'X.Timer._ie_loop()';\r
+\r
+// ページを読み込んでからの時間\r
+function X_Timer_onEnterFrame( time ){\r
+ var list = X_Timer_REQ_FRAME_LIST,\r
+ l = list.length,\r
+ i = 0, q, uid;\r
+\r
+ time = time || X.getTime();\r
+ X_Timer_busyOnFrame = true;\r
+ // console.log( X.getTime() + ' , ' + time );\r
+ for( ; i < l; ++i ){\r
+ q = list[ i ];\r
+ \r
+ if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue;\r
+ \r
+ if( q.k ){\r
+ q.a = [ time ];\r
+ X.Callback._proxyCallback( q );\r
+ } else {\r
+ q( time );\r
+ };\r
+ };\r
+\r
+ list.splice( 0, l );\r
+ if( list.length ){\r
+ X_Timer_requestID = X_Timer_REQ_ANIME_FRAME ? X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) : X.Timer.add( 0, 1, X_Timer_onEnterFrame );\r
+ };\r
+ \r
+ X_Timer_busyOnFrame = false;\r
+ if( X_Timer_removal ){\r
+ for( uid in X_Timer_removal ){\r
+ X.Timer.cancelFrame( X_Timer_removal[ uid ] );\r
+ };\r
+ X_Timer_removal = null;\r
+ };\r
+};\r
+\r
+// 大きい -> 小さい\r
+function X_Timer_compareQueue( a, b ){\r
+ return a.last < b.last ? 1 : a.last === b.last ? 0 : -1;\r
};\r
\r
+\r
console.log( 'X.Core.Timer' );\r