Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Namespace | |
| 6 var importer = importer || {}; | |
| 7 | |
| 8 /** | |
| 9 * A queue of tasks. Tasks (subclasses of TaskQueue.Task) can be pushed onto | |
| 10 * the queue. The queue becomes active whenever it is not empty, and it will | |
| 11 * begin executing tasks one at a time. As each task runs, it can send update | |
| 12 * notifications which are relayed back to clients via callbacks. When the | |
| 13 * queue runs of of tasks, it goes back into an idle state. Clients can set | |
| 14 * callbacks which will be triggered whenever the queue transitions between the | |
| 15 * active and idle states. | |
| 16 * | |
| 17 * @constructor | |
|
hirono
2014/12/15 00:20:07
Please add @struct also.
Ben Kwa
2014/12/15 16:53:00
Done.
| |
| 18 */ | |
| 19 importer.TaskQueue = function() { | |
| 20 /** @private {!Array<!importer.TaskQueue.Task>} */ | |
| 21 this.tasks_ = []; | |
| 22 | |
| 23 /** @private {!Array<!function(string, !importer.TaskQueue.Task)>} */ | |
| 24 this.updateCallbacks_ = []; | |
| 25 | |
| 26 /** @private {?function()} */ | |
| 27 this.activeCallback_ = null; | |
| 28 | |
| 29 /** @private {?function()} */ | |
| 30 this.idleCallback_ = null; | |
| 31 | |
| 32 /** @private {boolean} */ | |
| 33 this.active_ = false; | |
| 34 }; | |
| 35 | |
| 36 /** | |
| 37 * @enum {string} | |
| 38 */ | |
| 39 importer.TaskQueue.UpdateType = { | |
| 40 PROGRESS: 'PROGRESS', | |
| 41 SUCCESS: 'SUCCESS', | |
| 42 ERROR: 'ERROR' | |
| 43 }; | |
| 44 | |
| 45 /** | |
| 46 * @param {!importer.TaskQueue.Task} task | |
| 47 */ | |
| 48 importer.TaskQueue.prototype.queueTask = function(task) { | |
| 49 // TODO(kenobi): Use an AsyncGroup | |
| 50 Promise.resolve().then(function() { | |
| 51 task.setOwner(this); | |
| 52 this.tasks_.push(task); | |
| 53 // If more than one task is queued, then the queue is already running. | |
| 54 if (this.tasks_.length === 1) { | |
| 55 this.runPending_(); | |
| 56 } | |
| 57 }.bind(this)); | |
| 58 }; | |
| 59 | |
| 60 /** | |
| 61 * Sets a callback to be triggered when a task updates. | |
| 62 * @param {function(string, !importer.TaskQueue.Task)} callback | |
| 63 */ | |
| 64 importer.TaskQueue.prototype.addUpdateCallback = function(callback) { | |
| 65 this.updateCallbacks_.push(callback); | |
| 66 }; | |
| 67 | |
| 68 /** | |
| 69 * Sets a callback that is triggered each time the queue goes from an idle | |
| 70 * (i.e. empty with no running tasks) to an active (i.e. having a running task) | |
| 71 * state. | |
| 72 * @param {function()} callback | |
| 73 */ | |
| 74 importer.TaskQueue.prototype.setActiveCallback = function(callback) { | |
| 75 this.activeCallback_ = callback; | |
| 76 }; | |
| 77 | |
| 78 /** | |
| 79 * Sets a callback that is triggered each time the queue goes from an active to | |
| 80 * an idle state. Also see #onActive. | |
| 81 * @param {function()} callback | |
| 82 */ | |
| 83 importer.TaskQueue.prototype.setIdleCallback = function(callback) { | |
| 84 this.idleCallback_ = callback; | |
| 85 }; | |
| 86 | |
| 87 /** | |
| 88 * Sends out notifications when a task updates. This is meant to be called by | |
| 89 * the running tasks owned by this queue. | |
| 90 * @param {!importer.TaskQueue.UpdateType} updateType | |
| 91 * @param {!importer.TaskQueue.Task} task | |
| 92 */ | |
| 93 importer.TaskQueue.prototype.taskUpdate = function(updateType, task) { | |
| 94 this.updateCallbacks_.forEach(function(callback) { | |
| 95 callback.call(null, updateType, task); | |
| 96 }); | |
| 97 }; | |
| 98 | |
| 99 /** | |
| 100 * Sends out notifications when a task stops. Stopping could be due to | |
| 101 * successful completion, cancellation, or errors. This is meant to be called | |
| 102 * by the running tasks owned by this queue. | |
| 103 * @param {!importer.TaskQueue.UpdateType} reason | |
| 104 * @param {!importer.TaskQueue.Task} task | |
| 105 */ | |
| 106 importer.TaskQueue.prototype.taskDone = function(reason, task) { | |
| 107 // Remove the completed task from the queue. | |
| 108 this.tasks_.shift(); | |
|
hirono
2014/12/15 00:20:07
Do you assume this.tasks_[0] === task ? If so, how
Ben Kwa
2014/12/15 16:53:00
Nice observation. Thanks! Done.
| |
| 109 // Send updates to clients. | |
| 110 this.taskUpdate(reason, task); | |
| 111 // Run the next thing in the queue. | |
| 112 this.runPending_(); | |
| 113 }; | |
| 114 | |
| 115 /** | |
| 116 * Wakes the task queue up and runs the next pending task, or makes the queue go | |
| 117 * back to sleep if no tasks are pending. | |
| 118 * @private | |
| 119 */ | |
| 120 importer.TaskQueue.prototype.runPending_ = function() { | |
| 121 if (this.tasks_.length === 0) { | |
| 122 // All done - go back to idle. | |
| 123 this.active_ = false; | |
| 124 if (this.idleCallback_) | |
| 125 this.idleCallback_(); | |
| 126 return; | |
| 127 } | |
| 128 | |
| 129 if (!this.active_) { | |
| 130 // If the queue is currently idle, transition to active state. | |
| 131 this.active_ = true; | |
| 132 if (this.activeCallback_) | |
| 133 this.activeCallback_(); | |
| 134 } | |
| 135 | |
| 136 var nextTask = this.tasks_[0]; | |
| 137 nextTask.run(); | |
| 138 }; | |
| 139 | |
| 140 /** | |
| 141 * Interface for any Task that is to run on the TaskQueue. | |
| 142 * @interface | |
| 143 */ | |
| 144 importer.TaskQueue.Task = function() {}; | |
| 145 | |
| 146 /** | |
| 147 * Sets the TaskQueue that will own this task. The TaskQueue must call this | |
| 148 * prior to enqueuing a Task. | |
| 149 * @param {!importer.TaskQueue} owner | |
| 150 */ | |
| 151 importer.TaskQueue.Task.prototype.setOwner; | |
| 152 | |
| 153 /** | |
| 154 * Performs the actual work of the Task. Child classes should implement this. | |
| 155 */ | |
| 156 importer.TaskQueue.Task.prototype.run; | |
| 157 | |
| 158 /** | |
| 159 * Base class for importer tasks. | |
| 160 * @constructor | |
| 161 * @implements {importer.TaskQueue.Task} | |
| 162 * | |
| 163 * @param {string} taskId | |
| 164 */ | |
| 165 importer.TaskQueue.BaseTask = function(taskId) { | |
| 166 /** @private {string} */ | |
| 167 this.taskId_ = taskId; | |
| 168 /** @private {importer.TaskQueue} */ | |
| 169 this.owner_ = null; | |
| 170 }; | |
| 171 | |
| 172 /** | |
| 173 * Sets the TaskQueue that will own this task. The TaskQueue must call this | |
| 174 * prior to enqueuing a Task. | |
| 175 * @param {!importer.TaskQueue} owner | |
| 176 */ | |
| 177 importer.TaskQueue.BaseTask.prototype.setOwner = function(owner) { | |
| 178 this.owner_ = owner; | |
| 179 }; | |
| 180 | |
| 181 /** @override */ | |
| 182 importer.TaskQueue.BaseTask.prototype.run = function() {}; | |
| 183 | |
| 184 /** | |
| 185 * Sends progress notifications. Task subclasses should call this to report | |
| 186 * progress. | |
| 187 * @protected | |
| 188 */ | |
| 189 importer.TaskQueue.BaseTask.prototype.notifyProgress = function() { | |
| 190 this.owner_.taskUpdate(importer.TaskQueue.UpdateType.PROGRESS, this); | |
| 191 }; | |
| 192 | |
| 193 /** | |
| 194 * Sends success notifications. Task subclasses should call this to indicate | |
| 195 * when they successfully complete. Calling this results in the Task instance | |
| 196 * being dequeued. | |
| 197 * @protected | |
| 198 */ | |
| 199 importer.TaskQueue.BaseTask.prototype.notifySuccess = function() { | |
| 200 this.owner_.taskDone(importer.TaskQueue.UpdateType.SUCCESS, this); | |
| 201 }; | |
| 202 | |
| 203 /** | |
| 204 * Sends error notifications. Task subclasses should call this to indicate when | |
| 205 * an error occurs. Tasks are assumed to stop execution once they call | |
| 206 * notifyError (i.e. they will be dequeued). | |
| 207 * @protected | |
| 208 */ | |
| 209 importer.TaskQueue.BaseTask.prototype.notifyError = function() { | |
| 210 this.owner_.taskDone(importer.TaskQueue.UpdateType.ERROR, this); | |
| 211 }; | |
| OLD | NEW |