OSDN Git Service

Version 0.6.83, fix X.Type.isImage & X.Util.NinjaIframe.
[pettanr/clientJs.git] / 0.6.x / js / 00_core / 05_XTimer.js
index a5873d8..8f2c169 100644 (file)
  * use X.Callback\r
  */\r
 \r
-var _enterFrame =\r
+/*\r
+ * \r
+ * http://please-sleep.cou929.nu/script-yielding-with-setimmediate.html\r
+ * setImmediate での script yielding\r
+ * \r
+ * http://ie.microsoft.com/testdrive/Performance/setImmediateSorting/Default.html\r
+ * setImmediate API\r
+ * \r
+ * if( timer < 4ms ) useSetImmediate\r
+ * \r
+ *         if (window.msSetImmediate)\r
+        {\r
+            this.timer = msSetImmediate(function () { t.stepper(); });        \r
+        }\r
+        else if (window.MozSetImmediate)\r
+        {\r
+            this.timer = MozSetImmediate(function () { t.stepper(); });        \r
+        }\r
+        else if (window.WebkitSetImmediate) {\r
+            this.timer = WebkitSetImmediate(function () { t.stepper(); });\r
+        }\r
+        else if (window.OSetImmediate)\r
+        {\r
+            this.timer = OSetImmediate(function () { t.stepper(); });        \r
+        }\r
+ */\r
+\r
+\r
+// ------------------------------------------------------------------------- //\r
+// ------------ local variables -------------------------------------------- //\r
+// ------------------------------------------------------------------------- //\r
+\r
+var X_Timer_SET_TIMEOUT   = window.setTimeout,\r
+       X_Timer_CLEAR_TIMEOUT = window.clearTimeout,\r
+       \r
+       X_Timer_REQ_ANIME_FRAME =\r
                window.requestAnimationFrame ||\r
                window.webkitRequestAnimationFrame ||\r
                window.mozRequestAnimationFrame ||\r
                window.oRequestAnimationFrame ||\r
                window.msRequestAnimationFrame ||\r
                false,\r
-       _cancelFrame =\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
-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
-       //frameBusy      : false,\r
-       \r
-       REQ_FRAME_LIST : [],\r
-       requestID      : 0,\r
-       \r
-       _loop : function(){\r
-               var next = X.Timer.next,\r
-                       list = X.Timer.TICKET_LIST,\r
-                       i    = list.length,\r
-                       q, f, c, r;\r
-               \r
-               if( X.Timer.busy ){\r
-                       alert( 'busy!' );\r
-               };\r
-               \r
-               X.Timer.busy = true;\r
+               false,\r
                \r
-           for( ; i; ){\r
-               q = list[ --i ];\r
-                       if( 0 < ( q.last -= next ) ) continue;\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
-                       if( r & X.Callback.UN_LISTEN || c === 1 ){\r
-                               list.splice( i, 1 );\r
-                               //f.kill && f.kill();\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    = Infinity,\r
-                       l;\r
-               if( i === 0 ){\r
-                       X.Timer.timerId && window.clearTimeout( X.Timer.timerId );\r
-                       X.Timer.timerId = 0;\r
-                       return;\r
-               };\r
-           for( ; i; ){\r
-               ( l = list[ --i ].last ) < n && ( n = l );\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
-               //this.frameBusy = true;\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
-               //delete f.uid;\r
-               //f.kill && f.kill();\r
-           };\r
-           //this.frameBusy = false;\r
-           list.splice( 0, l );\r
-           if( list.length ) X.Timer.requestID = _enterFrame( X.Timer._onEnterFrame );\r
-       },\r
+       X_Timer_REQ_FRAME_LIST = [],\r
+       X_Timer_requestID      = 0,\r
+       X_Timer_busyOnFrame    = false;\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
@@ -132,102 +90,243 @@ X.Timer = {
                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
-                               //f = q.f;\r
-                               //f.kill && f.kill();\r
-                               !X.Timer.busy && ( /* q[ INDEX_COUNT ] <= next  || */ l === 1 ) && X.Timer._update();\r
-                               //q.length = 0;\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
-                                       //delete f.uid;\r
-                                       //f.kill && f.kill();\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
-                                       //delete f.uid;\r
-                                       //f.kill && f.kill();\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
+// --- 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