src/cm/media/js/lib/yui/yui3-3.15.0/build/timers/timers.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('timers', function (Y, NAME) {
       
     2 
       
     3 /**
       
     4 Provides utilities for timed asynchronous callback execution.
       
     5 Y.soon is a setImmediate/process.nextTick/setTimeout wrapper.
       
     6 
       
     7 This module includes [asap.js](https://github.com/kriskowal/asap) for scheduling
       
     8 asynchronous tasks.
       
     9 
       
    10 @module timers
       
    11 @author Steven Olmsted
       
    12 **/
       
    13 
       
    14 // Hack. asap.js is written as a Node module and expects require, module and
       
    15 // global to be available in the module's scope.
       
    16 var module = {},
       
    17     global = Y.config.global;
       
    18 
       
    19 // `asap` only requires a `queue` module that is bundled into this same file.
       
    20 function require(mod) {
       
    21     return Queue;
       
    22 }
       
    23 "use strict";
       
    24 
       
    25 module.exports = Queue;
       
    26 function Queue(capacity) {
       
    27     this.capacity = this.snap(capacity);
       
    28     this.length = 0;
       
    29     this.front = 0;
       
    30     this.initialize();
       
    31 }
       
    32 
       
    33 Queue.prototype.push = function (value) {
       
    34     var length = this.length;
       
    35     if (this.capacity <= length) {
       
    36         this.grow(this.snap(this.capacity * this.growFactor));
       
    37     }
       
    38     var index = (this.front + length) & (this.capacity - 1);
       
    39     this[index] = value;
       
    40     this.length = length + 1;
       
    41 };
       
    42 
       
    43 Queue.prototype.shift = function () {
       
    44     var front = this.front;
       
    45     var result = this[front];
       
    46 
       
    47     this[front] = void 0;
       
    48     this.front = (front + 1) & (this.capacity - 1);
       
    49     this.length--;
       
    50     return result;
       
    51 };
       
    52 
       
    53 Queue.prototype.grow = function (capacity) {
       
    54     var oldFront = this.front;
       
    55     var oldCapacity = this.capacity;
       
    56     var oldQueue = new Array(oldCapacity);
       
    57     var length = this.length;
       
    58 
       
    59     copy(this, 0, oldQueue, 0, oldCapacity);
       
    60     this.capacity = capacity;
       
    61     this.initialize();
       
    62     this.front = 0;
       
    63     if (oldFront + length <= oldCapacity) {
       
    64         // Can perform direct linear copy
       
    65         copy(oldQueue, oldFront, this, 0, length);
       
    66     } else {
       
    67         // Cannot perform copy directly, perform as much as possible at the
       
    68         // end, and then copy the rest to the beginning of the buffer
       
    69         var lengthBeforeWrapping =
       
    70             length - ((oldFront + length) & (oldCapacity - 1));
       
    71         copy(
       
    72             oldQueue,
       
    73             oldFront,
       
    74             this,
       
    75             0,
       
    76             lengthBeforeWrapping
       
    77         );
       
    78         copy(
       
    79             oldQueue,
       
    80             0,
       
    81             this,
       
    82             lengthBeforeWrapping,
       
    83             length - lengthBeforeWrapping
       
    84         );
       
    85     }
       
    86 };
       
    87 
       
    88 Queue.prototype.initialize = function () {
       
    89     var length = this.capacity;
       
    90     for (var i = 0; i < length; ++i) {
       
    91         this[i] = void 0;
       
    92     }
       
    93 };
       
    94 
       
    95 Queue.prototype.snap = function (capacity) {
       
    96     if (typeof capacity !== "number") {
       
    97         return this.minCapacity;
       
    98     }
       
    99     return pow2AtLeast(
       
   100         Math.min(this.maxCapacity, Math.max(this.minCapacity, capacity))
       
   101     );
       
   102 };
       
   103 
       
   104 Queue.prototype.maxCapacity = (1 << 30) | 0;
       
   105 Queue.prototype.minCapacity = 16;
       
   106 Queue.prototype.growFactor = 8;
       
   107 
       
   108 function copy(source, sourceIndex, target, targetIndex, length) {
       
   109     for (var index = 0; index < length; ++index) {
       
   110         target[index + targetIndex] = source[index + sourceIndex];
       
   111     }
       
   112 }
       
   113 
       
   114 function pow2AtLeast(n) {
       
   115     n = n >>> 0;
       
   116     n = n - 1;
       
   117     n = n | (n >> 1);
       
   118     n = n | (n >> 2);
       
   119     n = n | (n >> 4);
       
   120     n = n | (n >> 8);
       
   121     n = n | (n >> 16);
       
   122     return n + 1;
       
   123 }
       
   124 "use strict";
       
   125 
       
   126 // Use the fastest possible means to execute a task in a future turn
       
   127 // of the event loop.
       
   128 
       
   129 // Queue is a circular buffer with good locality of reference and doesn't
       
   130 // allocate new memory unless there are more than `InitialCapacity` parallel
       
   131 // tasks in which case it will resize itself generously to x8 more capacity.
       
   132 // The use case of asap should require no or few amount of resizes during
       
   133 // runtime.
       
   134 // Calling a task frees a slot immediately so if the calling
       
   135 // has a side effect of queuing itself again, it can be sustained
       
   136 // without additional memory
       
   137 // Queue specifically uses
       
   138 // http://en.wikipedia.org/wiki/Circular_buffer#Use_a_Fill_Count
       
   139 // Because:
       
   140 // 1. We need fast .length operation, since queue
       
   141 //   could have changed after every iteration
       
   142 // 2. Modulus can be negated by using power-of-two
       
   143 //   capacities and replacing it with bitwise AND
       
   144 // 3. It will not be used in a multi-threaded situation.
       
   145 
       
   146 var Queue = require("./queue");
       
   147 
       
   148 //1024 = InitialCapacity
       
   149 var queue = new Queue(1024);
       
   150 var flushing = false;
       
   151 var requestFlush = void 0;
       
   152 var hasSetImmediate = typeof setImmediate === "function";
       
   153 var domain;
       
   154 
       
   155 // Avoid shims from browserify.
       
   156 // The existence of `global` in browsers is guaranteed by browserify.
       
   157 var process = global.process;
       
   158 
       
   159 // Note that some fake-Node environments,
       
   160 // like the Mocha test runner, introduce a `process` global.
       
   161 var isNodeJS = !!process && ({}).toString.call(process) === "[object process]";
       
   162 
       
   163 function flush() {
       
   164     /* jshint loopfunc: true */
       
   165 
       
   166     while (queue.length > 0) {
       
   167         var task = queue.shift();
       
   168 
       
   169         try {
       
   170             task.call();
       
   171 
       
   172         } catch (e) {
       
   173             if (isNodeJS) {
       
   174                 // In node, uncaught exceptions are considered fatal errors.
       
   175                 // Re-throw them to interrupt flushing!
       
   176 
       
   177                 // Ensure continuation if an uncaught exception is suppressed
       
   178                 // listening process.on("uncaughtException") or domain("error").
       
   179                 requestFlush();
       
   180 
       
   181                 throw e;
       
   182 
       
   183             } else {
       
   184                 // In browsers, uncaught exceptions are not fatal.
       
   185                 // Re-throw them asynchronously to avoid slow-downs.
       
   186                 setTimeout(function () {
       
   187                     throw e;
       
   188                 }, 0);
       
   189             }
       
   190         }
       
   191     }
       
   192 
       
   193     flushing = false;
       
   194 }
       
   195 
       
   196 if (isNodeJS) {
       
   197     // Node.js
       
   198     requestFlush = function () {
       
   199         // Ensure flushing is not bound to any domain.
       
   200         var currentDomain = process.domain;
       
   201         if (currentDomain) {
       
   202             domain = domain || (1,require)("domain");
       
   203             domain.active = process.domain = null;
       
   204         }
       
   205 
       
   206         // Avoid tick recursion - use setImmediate if it exists.
       
   207         if (flushing && hasSetImmediate) {
       
   208             setImmediate(flush);
       
   209         } else {
       
   210             process.nextTick(flush);
       
   211         }
       
   212 
       
   213         if (currentDomain) {
       
   214             domain.active = process.domain = currentDomain;
       
   215         }
       
   216     };
       
   217 
       
   218 } else if (hasSetImmediate) {
       
   219     // In IE10, or https://github.com/NobleJS/setImmediate
       
   220     requestFlush = function () {
       
   221         setImmediate(flush);
       
   222     };
       
   223 
       
   224 } else if (typeof MessageChannel !== "undefined") {
       
   225     // modern browsers
       
   226     // http://www.nonblocking.io/2011/06/windownexttick.html
       
   227     var channel = new MessageChannel();
       
   228     // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create
       
   229     // working message ports the first time a page loads.
       
   230     channel.port1.onmessage = function () {
       
   231         requestFlush = requestPortFlush;
       
   232         channel.port1.onmessage = flush;
       
   233         flush();
       
   234     };
       
   235     var requestPortFlush = function () {
       
   236         // Opera requires us to provide a message payload, regardless of
       
   237         // whether we use it.
       
   238         channel.port2.postMessage(0);
       
   239     };
       
   240     requestFlush = function () {
       
   241         setTimeout(flush, 0);
       
   242         requestPortFlush();
       
   243     };
       
   244 
       
   245 } else {
       
   246     // old browsers
       
   247     requestFlush = function () {
       
   248         setTimeout(flush, 0);
       
   249     };
       
   250 }
       
   251 
       
   252 function asap(task) {
       
   253     if (isNodeJS && process.domain) {
       
   254         task = process.domain.bind(task);
       
   255     }
       
   256 
       
   257     queue.push(task);
       
   258 
       
   259     if (!flushing) {
       
   260         requestFlush();
       
   261         flushing = true;
       
   262     }
       
   263 };
       
   264 
       
   265 module.exports = asap;
       
   266 /**
       
   267 Y.soon accepts a callback function.  The callback function will be called
       
   268 once in a future turn of the JavaScript event loop.  If the function
       
   269 requires a specific execution context or arguments, wrap it with Y.bind.
       
   270 Y.soon returns an object with a cancel method.  If the cancel method is
       
   271 called before the callback function, the callback function won't be
       
   272 called.
       
   273 
       
   274 @method soon
       
   275 @for YUI
       
   276 @param {Function} callbackFunction
       
   277 @return {Object} An object with a cancel method.  If the cancel method is
       
   278     called before the callback function, the callback function won't be
       
   279     called.
       
   280 **/
       
   281 function soon(callbackFunction) {
       
   282     var canceled;
       
   283 
       
   284     soon._asynchronizer(function () {
       
   285         // Some asynchronizers may provide their own cancellation
       
   286         // methods such as clearImmediate or clearTimeout but some
       
   287         // asynchronizers do not.  For simplicity, cancellation is
       
   288         // entirely handled here rather than wrapping the other methods.
       
   289         // All asynchronizers are expected to always call this anonymous
       
   290         // function.
       
   291         if (!canceled) {
       
   292             callbackFunction();
       
   293         }
       
   294     });
       
   295 
       
   296     return {
       
   297         cancel: function () {
       
   298             canceled = 1;
       
   299         }
       
   300     };
       
   301 }
       
   302 
       
   303 soon._asynchronizer = asap;
       
   304 soon._impl = 'asap';
       
   305 
       
   306 Y.soon = soon;
       
   307 
       
   308 
       
   309 }, '@VERSION@', {"requires": ["yui-base"]});