// ------------ local variables -------------------------------------------- //\r
// ------------------------------------------------------------------------- //\r
\r
-var X_Timer_SET_TIMEOUT = window.setTimeout,\r
+var X_Timer_now = Date.now || function(){ return +new Date; },\r
+\r
+ X_Timer_SET_TIMEOUT = window.setTimeout,\r
X_Timer_CLEAR_TIMEOUT = window.clearTimeout,\r
- \r
+\r
+ // http://uupaa.hatenablog.com/entry/2012/02/01/083607\r
+ // Firefox 4 partial (request only), Mobile Firefox5 ready (request only), Firefox 11 ready (cancel impl) \r
X_Timer_REQ_ANIME_FRAME =\r
window.requestAnimationFrame ||\r
window.webkitRequestAnimationFrame ||\r
window.oRequestAnimationFrame ||\r
window.msRequestAnimationFrame ||\r
false,\r
+\r
X_Timer_CANCEL_ANIME_FRAME =\r
window.cancelRequestAnimationFrame ||\r
window.webkitCancelAnimationFrame ||\r
X_Timer_INTERVAL_TIME = 16,\r
X_Timer_TICKET_LIST = [],\r
X_Timer_removal = null,\r
+ X_Timer_skipUpdate = false,\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
+ X_Timer_busyTimeout = false,\r
+ X_Timer_timeStamp = 0, // setTimeout に登録した時間\r
+ X_Timer_waitTime = 0, // 待ち時間\r
+ X_Timer_currentUID = 0, // 現在発火中の uid\r
\r
X_Timer_REQ_FRAME_LIST = [],\r
X_Timer_requestID = 0,\r
// ------------------------------------------------------------------------- //\r
X.Timer = {\r
\r
+ now : X_Timer_now,\r
+ \r
add : function( time, opt_count, args1, args2, args3 ){\r
var list = X_Timer_TICKET_LIST,\r
hash, obj;\r
var list = X_Timer_TICKET_LIST,\r
i = list.length,\r
l = i,\r
- f, q;\r
+ f, q, eventDispatcher, lazy, listeners;\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
+ \r
+ /*\r
+ * lazyDispatch 中の EventDispatcher の有無を調べる\r
+ */\r
+ if( X_EventDispatcher_LAZY_TIMERS[ uid ] ){\r
+ eventDispatcher = X_EventDispatcher_LAZY_TIMERS[ uid ];\r
+ delete X_EventDispatcher_LAZY_TIMERS[ uid ];\r
+ \r
+ listeners = eventDispatcher[ '_listeners' ];\r
+ if( listeners && !listeners._dispatching && listeners._killReserved ){\r
+ for( uid in X_EventDispatcher_LAZY_TIMERS ){\r
+ if( X_EventDispatcher_LAZY_TIMERS[ uid ] === eventDispatcher ){\r
+ lazy = true;\r
+ break;\r
+ };\r
+ }; \r
+ !lazy && eventDispatcher.kill();\r
+ };\r
+ };\r
+ \r
+ !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update();\r
break;\r
};\r
}; \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
+ // gecko では無い場合がある\r
+ l === 1 && X_Timer_CANCEL_ANIME_FRAME && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
break;\r
};\r
}; \r
// --- implements ---------------------------------------------------------- //\r
// ------------------------------------------------------------------------- //\r
\r
-if( X.UA.IE4 || X.UA.MacIE ){\r
+if( X_UA.IE4 || 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
+ var now = X_Timer_now(),\r
+ minus = ( ( now - X_Timer_timeStamp ) / X_Timer_INTERVAL_TIME | 0 ) || 1,\r
list = X_Timer_TICKET_LIST,\r
i = 0,\r
l = list.length,\r
- limit = X.getTime() + X_Timer_INTERVAL_TIME / 2,\r
+ limit = now + X_Timer_INTERVAL_TIME / 2,\r
heavy,\r
q, f, c, r, uid;\r
\r
+ //console.log( '予定時間と発火時間の差:' + ( now - X_Timer_timeStamp - X_Timer_waitTime * X_Timer_INTERVAL_TIME ) + ' -:' + minus + ' next:' + X_Timer_waitTime );\r
+ \r
if( X_Timer_busyTimeout ){\r
- alert( 'busy!' );\r
+ alert( 'X_Timer_busyTimeout フラグが立ったまま!エラーの可能性' );\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
+ if(\r
+ ( X_Timer_removal && X_Timer_removal[ q.uid ] ) || // timerId は remove 登録されている\r
+ 0 < ( q.last -= minus ) || // 時間が経過していない\r
+ heavy && ( q.last = 1 ) // 時間は経過したが、ヘビーフラグが立っている\r
+ ){\r
continue;\r
};\r
c = q.count;\r
\r
+ X_Timer_currentUID = q.uid;\r
+ \r
if( q.k ){\r
- //q.a = [];\r
r = X_Callback_proxyCallback( q, [] );\r
} else {\r
r = q.f();\r
\r
//console.log( 'fire....' );\r
\r
- if( limit <= X.getTime() ){\r
- console.log( '******* heavy!' );\r
+ if( limit <= X_Timer_now() ){\r
+ //console.log( '******* heavy!' );\r
// 関数の実行に時間がかかる場合、次のタイミングに\r
heavy = true;\r
};\r
if( 1 < c ) --q.count;\r
q.last = q.time;\r
};\r
- X_Timer_timerId = 0;\r
+ X_Timer_timerId = X_Timer_currentUID = 0;\r
X_Timer_busyTimeout = false;\r
+ \r
if( X_Timer_removal ){\r
+ X_Timer_skipUpdate = true;\r
for( uid in X_Timer_removal ){\r
- X.Timer.remove( X_Timer_removal[ uid ] );\r
+ //if( X_EMPTY_OBJECT[ uid ] ) continue;\r
+ X.Timer.remove( uid );\r
};\r
+ X_Timer_skipUpdate = false;\r
X_Timer_removal = null;\r
};\r
X_Timer_update();\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
+ if( n < X_Timer_waitTime || X_Timer_timerId === 0 ){\r
+ if( X_Timer_timerId ){\r
+ X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );\r
+ n -= ( X_Timer_now() - X_Timer_timeStamp ) / X_Timer_INTERVAL_TIME | 0;\r
+ 0 <= n || ( n = 0 ); // 負の数は 0 に\r
+ };\r
+ X_Timer_timeStamp = X_Timer_now();\r
+ X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, X_Timer_INTERVAL_TIME * n );\r
+ X_Timer_waitTime = n;\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
// http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html\r
// iOS6 スクロール中のタイマー発火絡みのバグ備忘\r
-if( X.UA.iOS ){\r
+if( X_UA.iOS ){\r
window.addEventListener( 'scroll', function(){\r
- var last;\r
+ var last, now;\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
+ X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );\r
+ now = X_Timer_now();\r
+ last = X_Timer_timeStamp + X_Timer_INTERVAL_TIME * X_Timer_waitTime - now;\r
+ X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 );\r
+ // 更新\r
+ X_Timer_timeStamp = now;\r
+ X_Timer_waitTime = last / X_Timer_INTERVAL_TIME | 0;\r
};\r
});\r
};\r
l = list.length,\r
i = 0, q, uid, args;\r
\r
- time = time || X.getTime();\r
+ time = time || X_Timer_now();\r
X_Timer_busyOnFrame = true;\r
- // console.log( X.getTime() + ' , ' + time );\r
+ // console.log( X_Timer_now() + ' , ' + time );\r
for( ; i < l; ++i ){\r
q = list[ i ];\r
\r
X_Timer_busyOnFrame = false;\r
if( X_Timer_removal ){\r
for( uid in X_Timer_removal ){\r
+ //if( X_EMPTY_OBJECT[ uid ] ) continue;\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