7 * http://please-sleep.cou929.nu/script-yielding-with-setimmediate.html
\r
8 * setImmediate での script yielding
\r
10 * http://ie.microsoft.com/testdrive/Performance/setImmediateSorting/Default.html
\r
13 * if( timer < 4ms ) useSetImmediate
\r
15 * if (window.msSetImmediate)
\r
17 this.timer = msSetImmediate(function () { t.stepper(); });
\r
19 else if (window.MozSetImmediate)
\r
21 this.timer = MozSetImmediate(function () { t.stepper(); });
\r
23 else if (window.WebkitSetImmediate) {
\r
24 this.timer = WebkitSetImmediate(function () { t.stepper(); });
\r
26 else if (window.OSetImmediate)
\r
28 this.timer = OSetImmediate(function () { t.stepper(); });
\r
33 // ------------------------------------------------------------------------- //
\r
34 // ------------ local variables -------------------------------------------- //
\r
35 // ------------------------------------------------------------------------- //
\r
37 var X_Timer_SET_TIMEOUT = window.setTimeout,
\r
38 X_Timer_CLEAR_TIMEOUT = window.clearTimeout,
\r
40 X_Timer_REQ_ANIME_FRAME =
\r
41 window.requestAnimationFrame ||
\r
42 window.webkitRequestAnimationFrame ||
\r
43 window.mozRequestAnimationFrame ||
\r
44 window.oRequestAnimationFrame ||
\r
45 window.msRequestAnimationFrame ||
\r
47 X_Timer_CANCEL_ANIME_FRAME =
\r
48 window.cancelRequestAnimationFrame ||
\r
49 window.webkitCancelAnimationFrame ||
\r
50 window.webkitCancelRequestAnimationFrame ||
\r
51 window.mozCancelRequestAnimationFrame ||
\r
52 window.oCancelRequestAnimationFrame ||
\r
53 window.msCancelRequestAnimationFrame ||
\r
56 X_Timer_INTERVAL_TIME = 16,
\r
57 X_Timer_TICKET_LIST = [],
\r
58 X_Timer_removal = null,
\r
60 X_Timer_timerId = 0,
\r
62 X_Timer_busyTimeout = false,
\r
63 X_Timer_endTime = 0, // iOS
\r
65 X_Timer_REQ_FRAME_LIST = [],
\r
66 X_Timer_requestID = 0,
\r
67 X_Timer_busyOnFrame = false;
\r
69 // ------------------------------------------------------------------------- //
\r
70 // --- interface ----------------------------------------------------------- //
\r
71 // ------------------------------------------------------------------------- //
\r
74 add : function( time, opt_count, args1, args2, args3 ){
\r
75 var list = X_Timer_TICKET_LIST,
\r
77 time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;
\r
79 if( !X.Type.isNumber( opt_count ) ){
\r
86 hash = X.Callback._classifyCallbackArgs( args1, args2, args3 );
\r
87 if( !hash ) return -1; // dev only
\r
89 if( !hash.k ) hash = { f : hash };
\r
92 hash.count = opt_count;
\r
93 hash.uid = ++X_Timer_uid;
\r
94 list[ list.length ] = hash;
\r
96 !X_Timer_busyTimeout && X_Timer_update();
\r
100 once : function( time, args1, args2, args3 ){
\r
101 return X.Timer.add( time, 1, args1, args2, args3 );
\r
104 remove : function( uid ){
\r
105 var list = X_Timer_TICKET_LIST,
\r
110 if( X_Timer_busyTimeout ){
\r
111 if( !X_Timer_removal ) X_Timer_removal = {};
\r
112 X_Timer_removal[ uid ] = true;
\r
116 if( ( q = list[ --i ] ).uid === uid ){
\r
117 list.splice( i, 1 );
\r
118 ( /* q[ INDEX_COUNT ] <= next || */ l === 1 ) && X_Timer_update();
\r
125 requestFrame : X_Timer_REQ_ANIME_FRAME ?
\r
126 (function( args1, args2, args3 ){
\r
127 var i = X_Timer_REQ_FRAME_LIST.length,
\r
129 i === 0 && ( X_Timer_requestID = X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) );
\r
130 f = X_Timer_REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );
\r
131 return f.uid = ++X_Timer_uid;
\r
133 (function( args1, args2, args3 ){
\r
134 var i = X_Timer_REQ_FRAME_LIST.length,
\r
136 i === 0 && ( X_Timer_requestID = X.Timer.add( 0, 1, X_Timer_onEnterFrame ) );
\r
137 f = X_Timer_REQ_FRAME_LIST[ i ] = X.Callback._classifyCallbackArgs( args1, args2, args3 );
\r
138 return f.uid = ++X_Timer_uid;
\r
141 cancelFrame : X_Timer_CANCEL_ANIME_FRAME ?
\r
143 var list = X_Timer_REQ_FRAME_LIST,
\r
148 if( X_Timer_busyOnFrame ){
\r
149 if( !X_Timer_removal ) X_Timer_removal = {};
\r
150 X_Timer_removal[ uid ] = true;
\r
153 if( ( f = list[ --i ] ).uid < uid ) break;
\r
154 if( f.uid === uid ){
\r
155 list.splice( i, 1 );
\r
156 l === 1 && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );
\r
163 var list = X_Timer_REQ_FRAME_LIST,
\r
168 if( X_Timer_busyOnFrame ){
\r
169 if( !X_Timer_removal ) X_Timer_removal = {};
\r
170 X_Timer_removal[ uid ] = true;
\r
173 if( ( f = list[ --i ] ).uid < uid ) break;
\r
174 if( f.uid === uid ){
\r
175 list.splice( i, 1 );
\r
176 l === 1 && X.Timer.remove( X_Timer_requestID );
\r
185 // ------------------------------------------------------------------------- //
\r
186 // --- implements ---------------------------------------------------------- //
\r
187 // ------------------------------------------------------------------------- //
\r
189 if( X.UA.IE4 || X.UA.MacIE ){
\r
190 X.Timer[ '_' ] = X_Timer_onTimeout;
\r
191 X_Timer_onTimeout = 'X.Timer._()';
\r
194 function X_Timer_onTimeout(){
\r
195 var next = X_Timer_next,
\r
196 list = X_Timer_TICKET_LIST,
\r
199 limit = X.getTime() + X_Timer_INTERVAL_TIME / 2,
\r
203 if( X_Timer_busyTimeout ){
\r
207 X_Timer_busyTimeout = true;
\r
209 for( ; i < l; ++i ){
\r
211 if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue;
\r
212 if( 0 < ( q.last -= next ) ) continue;
\r
214 if( q.last <= 0 ) q.last = 1;
\r
221 r = X.Callback._proxyCallback( q );
\r
226 //console.log( 'fire....' );
\r
228 if( limit <= X.getTime() ){
\r
229 console.log( '******* heavy!' );
\r
230 // 関数の実行に時間がかかる場合、次のタイミングに
\r
234 if( r & X.Callback.UN_LISTEN || c === 1 ){
\r
235 list.splice( i, 1 );
\r
240 if( 1 < c ) --q.count;
\r
243 X_Timer_timerId = 0;
\r
244 X_Timer_busyTimeout = false;
\r
245 if( X_Timer_removal ){
\r
246 for( uid in X_Timer_removal ){
\r
247 X.Timer.remove( X_Timer_removal[ uid ] );
\r
249 X_Timer_removal = null;
\r
254 function X_Timer_update(){
\r
255 var list = X_Timer_TICKET_LIST,
\r
259 X_Timer_timerId && X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );
\r
260 X_Timer_timerId = 0;
\r
264 1 < i && list.sort( X_Timer_compareQueue );
\r
266 n = list[ i - 1 ].last;
\r
268 if( n < X_Timer_next || X_Timer_timerId === 0 ){
\r
269 X_Timer_timerId && X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );
\r
270 X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, X_Timer_INTERVAL_TIME * n );
\r
271 X_Timer_endTime = X.getTime() + X_Timer_INTERVAL_TIME * n; // iOS
\r
276 // http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html
\r
277 // iOS6 スクロール中のタイマー発火絡みのバグ備忘
\r
279 window.addEventListener( 'scroll', function(){
\r
281 if( X_Timer_timerId ){
\r
282 window.clearTimeout( X_Timer_timerId );
\r
283 last = X_Timer_endTime - X.getTime();
\r
284 X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 );
\r
291 function X_Timer_onEnterFrame( time ){
\r
292 var list = X_Timer_REQ_FRAME_LIST,
\r
296 time = time || X.getTime();
\r
297 X_Timer_busyOnFrame = true;
\r
298 // console.log( X.getTime() + ' , ' + time );
\r
299 for( ; i < l; ++i ){
\r
302 if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue;
\r
306 X.Callback._proxyCallback( q );
\r
312 list.splice( 0, l );
\r
314 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
317 X_Timer_busyOnFrame = false;
\r
318 if( X_Timer_removal ){
\r
319 for( uid in X_Timer_removal ){
\r
320 X.Timer.cancelFrame( X_Timer_removal[ uid ] );
\r
322 X_Timer_removal = null;
\r
327 function X_Timer_compareQueue( a, b ){
\r
328 return a.last < b.last ? 1 : a.last === b.last ? 0 : -1;
\r
332 console.log( 'X.Core.Timer' );
\r