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 |