123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>The source code</title>
- <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
- <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
- <style type="text/css">
- .highlight { display: block; background-color: #ddd; }
- </style>
- <script type="text/javascript">
- function highlight() {
- document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
- }
- </script>
- </head>
- <body onload="prettyPrint(); highlight();">
- <pre class="prettyprint lang-js"><span id='Ext-util-TaskRunner-method-constructor'><span id='Ext-util-TaskRunner'>/**
- </span></span> * Provides the ability to execute one or more arbitrary tasks in a asynchronous manner.
- * Generally, you can use the singleton {@link Ext.TaskManager} instead, but if needed,
- * you can create separate instances of TaskRunner. Any number of separate tasks can be
- * started at any time and will run independently of each other.
- *
- * Example usage:
- *
- * // Start a simple clock task that updates a div once per second
- * var updateClock = function () {
- * Ext.fly('clock').update(new Date().format('g:i:s A'));
- * }
- *
- * var runner = new Ext.util.TaskRunner();
- * var task = runner.start({
- * run: updateClock,
- * interval: 1000
- * }
- *
- * The equivalent using TaskManager:
- *
- * var task = Ext.TaskManager.start({
- * run: updateClock,
- * interval: 1000
- * });
- *
- * To end a running task:
- *
- * Ext.TaskManager.stop(task);
- *
- * If a task needs to be started and stopped repeated over time, you can create a
- * {@link Ext.util.TaskRunner.Task Task} instance.
- *
- * var task = runner.newTask({
- * run: function () {
- * // useful code
- * },
- * interval: 1000
- * });
- *
- * task.start();
- *
- * // ...
- *
- * task.stop();
- *
- * // ...
- *
- * task.start();
- *
- * A re-usable, one-shot task can be managed similar to the above:
- *
- * var task = runner.newTask({
- * run: function () {
- * // useful code to run once
- * },
- * repeat: 1
- * });
- *
- * task.start();
- *
- * // ...
- *
- * task.start();
- *
- * See the {@link #start} method for details about how to configure a task object.
- *
- * Also see {@link Ext.util.DelayedTask}.
- *
- * @constructor
- * @param {Number/Object} [interval=10] The minimum precision in milliseconds supported by this
- * TaskRunner instance. Alternatively, a config object to apply to the new instance.
- */
- Ext.define('Ext.util.TaskRunner', {
- <span id='Ext-util-TaskRunner-cfg-interval'> /**
- </span> * @cfg interval
- * The timer resolution.
- */
- interval: 10,
- <span id='Ext-util-TaskRunner-property-timerId'> /**
- </span> * @property timerId
- * The id of the current timer.
- * @private
- */
- timerId: null,
- constructor: function (interval) {
- var me = this;
- if (typeof interval == 'number') {
- me.interval = interval;
- } else if (interval) {
- Ext.apply(me, interval);
- }
- me.tasks = [];
- me.timerFn = Ext.Function.bind(me.onTick, me);
- },
- <span id='Ext-util-TaskRunner-method-newTask'> /**
- </span> * Creates a new {@link Ext.util.TaskRunner.Task Task} instance. These instances can
- * be easily started and stopped.
- * @param {Object} config The config object. For details on the supported properties,
- * see {@link #start}.
- */
- newTask: function (config) {
- var task = new Ext.util.TaskRunner.Task(config);
- task.manager = this;
- return task;
- },
- <span id='Ext-util-TaskRunner-method-start'> /**
- </span> * Starts a new task.
- *
- * Before each invocation, Ext injects the property `taskRunCount` into the task object
- * so that calculations based on the repeat count can be performed.
- *
- * The returned task will contain a `destroy` method that can be used to destroy the
- * task and cancel further calls. This is equivalent to the {@link #stop} method.
- *
- * @param {Object} task A config object that supports the following properties:
- * @param {Function} task.run The function to execute each time the task is invoked. The
- * function will be called at each interval and passed the `args` argument if specified,
- * and the current invocation count if not.
- *
- * If a particular scope (`this` reference) is required, be sure to specify it using
- * the `scope` argument.
- *
- * @param {Function} task.onError The function to execute in case of unhandled
- * error on task.run.
- *
- * @param {Boolean} task.run.return `false` from this function to terminate the task.
- *
- * @param {Number} task.interval The frequency in milliseconds with which the task
- * should be invoked.
- *
- * @param {Object[]} task.args An array of arguments to be passed to the function
- * specified by `run`. If not specified, the current invocation count is passed.
- *
- * @param {Object} task.scope The scope (`this` reference) in which to execute the
- * `run` function. Defaults to the task config object.
- *
- * @param {Number} task.duration The length of time in milliseconds to invoke the task
- * before stopping automatically (defaults to indefinite).
- *
- * @param {Number} task.repeat The number of times to invoke the task before stopping
- * automatically (defaults to indefinite).
- * @return {Object} The task
- */
- start: function(task) {
- var me = this,
- now = new Date().getTime();
- if (!task.pending) {
- me.tasks.push(task);
- task.pending = true; // don't allow the task to be added to me.tasks again
- }
- task.stopped = false; // might have been previously stopped...
- task.taskStartTime = now;
- task.taskRunTime = task.fireOnStart !== false ? 0 : task.taskStartTime;
- task.taskRunCount = 0;
- if (!me.firing) {
- if (task.fireOnStart !== false) {
- me.startTimer(0, now);
- } else {
- me.startTimer(task.interval, now);
- }
- }
- return task;
- },
- <span id='Ext-util-TaskRunner-method-stop'> /**
- </span> * Stops an existing running task.
- * @param {Object} task The task to stop
- * @return {Object} The task
- */
- stop: function(task) {
- // NOTE: we don't attempt to remove the task from me.tasks at this point because
- // this could be called from inside a task which would then corrupt the state of
- // the loop in onTick
- if (!task.stopped) {
- task.stopped = true;
- if (task.onStop) {
- task.onStop.call(task.scope || task, task);
- }
- }
- return task;
- },
- <span id='Ext-util-TaskRunner-method-stopAll'> /**
- </span> * Stops all tasks that are currently running.
- */
- stopAll: function() {
- // onTick will take care of cleaning up the mess after this point...
- Ext.each(this.tasks, this.stop, this);
- },
- //-------------------------------------------------------------------------
- firing: false,
- nextExpires: 1e99,
- // private
- onTick: function () {
- var me = this,
- tasks = me.tasks,
- now = new Date().getTime(),
- nextExpires = 1e99,
- len = tasks.length,
- expires, newTasks, i, task, rt, remove;
- me.timerId = null;
- me.firing = true; // ensure we don't startTimer during this loop...
- // tasks.length can be > len if start is called during a task.run call... so we
- // first check len to avoid tasks.length reference but eventually we need to also
- // check tasks.length. we avoid repeating use of tasks.length by setting len at
- // that time (to help the next loop)
- for (i = 0; i < len || i < (len = tasks.length); ++i) {
- task = tasks[i];
- if (!(remove = task.stopped)) {
- expires = task.taskRunTime + task.interval;
- if (expires <= now) {
- rt = 1; // otherwise we have a stale "rt"
- try {
- rt = task.run.apply(task.scope || task, task.args || [++task.taskRunCount]);
- } catch (taskError) {
- try {
- if (task.onError) {
- rt = task.onError.call(task.scope || task, task, taskError);
- }
- } catch (ignore) { }
- }
- task.taskRunTime = now;
- if (rt === false || task.taskRunCount === task.repeat) {
- me.stop(task);
- remove = true;
- } else {
- remove = task.stopped; // in case stop was called by run
- expires = now + task.interval;
- }
- }
- if (!remove && task.duration && task.duration <= (now - task.taskStartTime)) {
- me.stop(task);
- remove = true;
- }
- }
- if (remove) {
- task.pending = false; // allow the task to be added to me.tasks again
- // once we detect that a task needs to be removed, we copy the tasks that
- // will carry forward into newTasks... this way we avoid O(N*N) to remove
- // each task from the tasks array (and ripple the array down) and also the
- // potentially wasted effort of making a new tasks[] even if all tasks are
- // going into the next wave.
- if (!newTasks) {
- newTasks = tasks.slice(0, i);
- // we don't set me.tasks here because callbacks can also start tasks,
- // which get added to me.tasks... so we will visit them in this loop
- // and account for their expirations in nextExpires...
- }
- } else {
- if (newTasks) {
- newTasks.push(task); // we've cloned the tasks[], so keep this one...
- }
- if (nextExpires > expires) {
- nextExpires = expires; // track the nearest expiration time
- }
- }
- }
- if (newTasks) {
- // only now can we copy the newTasks to me.tasks since no user callbacks can
- // take place
- me.tasks = newTasks;
- }
- me.firing = false; // we're done, so allow startTimer afterwards
- if (me.tasks.length) {
- // we create a new Date here because all the callbacks could have taken a long
- // time... we want to base the next timeout on the current time (after the
- // callback storm):
- me.startTimer(nextExpires - now, new Date().getTime());
- }
- },
- // private
- startTimer: function (timeout, now) {
- var me = this,
- expires = now + timeout,
- timerId = me.timerId;
- // Check to see if this request is enough in advance of the current timer. If so,
- // we reschedule the timer based on this new expiration.
- if (timerId && me.nextExpires - expires > me.interval) {
- clearTimeout(timerId);
- timerId = null;
- }
- if (!timerId) {
- if (timeout < me.interval) {
- timeout = me.interval;
- }
- me.timerId = setTimeout(me.timerFn, timeout);
- me.nextExpires = expires;
- }
- }
- },
- function () {
- var me = this,
- proto = me.prototype;
- <span id='Ext-util-TaskRunner-method-destroy'> /**
- </span> * Destroys this instance, stopping all tasks that are currently running.
- * @method destroy
- */
- proto.destroy = proto.stopAll;
- <span id='Ext-TaskManager'> /**
- </span> * @class Ext.TaskManager
- * @extends Ext.util.TaskRunner
- * @singleton
- *
- * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop
- * arbitrary tasks. See {@link Ext.util.TaskRunner} for supported methods and task
- * config properties.
- *
- * // Start a simple clock task that updates a div once per second
- * var task = {
- * run: function(){
- * Ext.fly('clock').update(new Date().format('g:i:s A'));
- * },
- * interval: 1000 //1 second
- * }
- *
- * Ext.TaskManager.start(task);
- *
- * See the {@link #start} method for details about how to configure a task object.
- */
- Ext.util.TaskManager = Ext.TaskManager = new me();
- <span id='Ext-util-TaskRunner-Task'> /**
- </span> * Instances of this class are created by {@link Ext.util.TaskRunner#newTask} method.
- *
- * For details on config properties, see {@link Ext.util.TaskRunner#start}.
- * @class Ext.util.TaskRunner.Task
- */
- me.Task = new Ext.Class({
- isTask: true,
- <span id='Ext-util-TaskRunner-Task-property-stopped'> /**
- </span> * This flag is set to `true` by {@link #stop}.
- * @private
- */
- stopped: true, // this avoids the odd combination of !stopped && !pending
- <span id='Ext-util-TaskRunner-Task-property-fireOnStart'> /**
- </span> * Override default behavior
- */
- fireOnStart: false,
- constructor: function (config) {
- Ext.apply(this, config);
- },
- <span id='Ext-util-TaskRunner-Task-method-restart'> /**
- </span> * Restarts this task, clearing it duration, expiration and run count.
- * @param {Number} [interval] Optionally reset this task's interval.
- */
- restart: function (interval) {
- if (interval !== undefined) {
- this.interval = interval;
- }
- this.manager.start(this);
- },
- <span id='Ext-util-TaskRunner-Task-method-start'> /**
- </span> * Starts this task if it is not already started.
- * @param {Number} [interval] Optionally reset this task's interval.
- */
- start: function (interval) {
- if (this.stopped) {
- this.restart(interval);
- }
- },
- <span id='Ext-util-TaskRunner-Task-method-stop'> /**
- </span> * Stops this task.
- */
- stop: function () {
- this.manager.stop(this);
- }
- });
- proto = me.Task.prototype;
- <span id='Ext-util-TaskRunner-Task-method-destroy'> /**
- </span> * Destroys this instance, stopping this task's execution.
- * @method destroy
- */
- proto.destroy = proto.stop;
- });
- </pre>
- </body>
- </html>
|