Chromium Code Reviews| Index: ui/file_manager/file_manager/common/js/async_util.js |
| diff --git a/ui/file_manager/file_manager/common/js/async_util.js b/ui/file_manager/file_manager/common/js/async_util.js |
| index f74a9d493810a66f18f1bb0705665d0dfe80ad0e..25ef4e58ca8f58525e6f5f0deb97884c0f362ecc 100644 |
| --- a/ui/file_manager/file_manager/common/js/async_util.js |
| +++ b/ui/file_manager/file_manager/common/js/async_util.js |
| @@ -43,57 +43,125 @@ AsyncUtil.forEach = function( |
| /** |
| * Creates a class for executing several asynchronous closures in a fifo queue. |
| - * Added tasks will be executed sequentially in order they were added. |
| + * Added tasks will be started in order they were added. Tasks are run |
| + * concurrently. At most, |limit| jobs will be run at the same time. |
| * |
| + * @param {number} limit The number of jobs to run at the same time. |
| * @constructor |
| */ |
| -AsyncUtil.Queue = function() { |
| - this.running_ = false; |
| - this.closures_ = []; |
| +AsyncUtil.ConcurrentQueue = function(limit) { |
| + console.assert(limit > 0, '|limit| must be larger than 2'); |
| + |
| + this.limit_ = limit; |
| + this.addedTasks_ = []; |
| + this.pendingTasks_ = []; |
| + this.isCancelled_ = false; |
| + |
| + Object.seal(this); |
| }; |
| /** |
| * @return {boolean} True when a task is running, otherwise false. |
| */ |
| -AsyncUtil.Queue.prototype.isRunning = function() { |
| - return this.running_; |
| +AsyncUtil.ConcurrentQueue.prototype.isRunning = function() { |
| + return this.pendingTasks_.length !== 0; |
| +}; |
| + |
| +/** |
| + * @return {number} Number of waiting tasks. |
| + */ |
| +AsyncUtil.ConcurrentQueue.prototype.getWaitingTasksCount = function() { |
| + return this.addedTasks_.length; |
| +}; |
| + |
| +/** |
| + * @return {boolean} Number of running tasks. |
| + */ |
| +AsyncUtil.ConcurrentQueue.prototype.getRunningTasksCount = function() { |
| + return this.pendingTasks_.length; |
| }; |
| /** |
| * Enqueues a closure to be executed. |
| - * @param {function(function())} closure Closure with a completion callback to |
| - * be executed. |
| + * @param {function(function(callback, isCancelled=))} closure Closure with a |
| + * completion callback to be executed. |
| */ |
| -AsyncUtil.Queue.prototype.run = function(closure) { |
| - this.closures_.push(closure); |
| - if (!this.running_) |
| - this.continue_(); |
| +AsyncUtil.ConcurrentQueue.prototype.run = function(closure) { |
| + if (this.isCancelled_) { |
| + console.error('Queue is calcelled. Cannot add a new task.'); |
| + return; |
| + } |
| + |
| + this.addedTasks_.push(closure); |
| + this.continue_(); |
| + return; |
|
hirono
2014/05/26 09:19:42
nit: Is it needed?
yoshiki
2014/05/26 09:36:33
Done.
|
| }; |
| /** |
| - * Serves the next closure from the queue. |
| + * Cancels the queue. It removes all the not-run (yet) tasks. Note that this |
| + * does NOT stop tasks currently running. |
| + */ |
| +AsyncUtil.ConcurrentQueue.prototype.cancel = function() { |
| + this.isCancelled_ = true; |
| + this.addedTasks_ = []; |
| +}; |
| + |
| +/** |
| + * @return {boolean} True when the queue have been requested to cancel or is |
| + * already cancelled. Otherwise false. |
| + */ |
| +AsyncUtil.ConcurrentQueue.prototype.isCancelled = function() { |
| + return this.isCancelled_; |
| +}; |
| + |
| +/** |
| + * Runs the next tasks if available. |
| * @private |
| */ |
| -AsyncUtil.Queue.prototype.continue_ = function() { |
| - if (!this.closures_.length) { |
| - this.running_ = false; |
| +AsyncUtil.ConcurrentQueue.prototype.continue_ = function() { |
| + if (this.addedTasks_.length === 0) |
| + return; |
| + |
| + console.assert( |
| + this.pendingTasks_.length <= this.limit_, |
| + 'Too many jobs are running (' + this.pendingTasks_.length + ')'); |
| + |
| + if (this.pendingTasks_.length >= this.limit_) |
| return; |
| - } |
| // Run the next closure. |
| - this.running_ = true; |
| - var closure = this.closures_.shift(); |
| - closure(this.continue_.bind(this)); |
| + var closure = this.addedTasks_.shift(); |
| + this.pendingTasks_.push(closure); |
| + closure(this.onTaskFinished_.bind(this, closure), this.isCancelled_); |
| + |
| + this.continue_(); |
| +}; |
| + |
| +/** |
| + * Called when a task is finished. Removes the tasks from pending task list. |
| + * @private |
| + */ |
| +AsyncUtil.ConcurrentQueue.prototype.onTaskFinished_ = function(closure) { |
| + var index = this.pendingTasks_.indexOf(closure); |
| + console.assert(index >= 0, 'Invalid task is finished'); |
| + this.pendingTasks_.splice(index, 1); |
| + |
| + this.continue_(); |
| }; |
| /** |
| - * Cancels all pending tasks. Note that this does NOT cancel the task running |
| - * currently. |
| + * Creates a class for executing several asynchronous closures in a fifo queue. |
| + * Added tasks will be executed sequentially in order they were added. |
| + * |
| + * @constructor |
| + * @extends {AsyncUtil.ConcurrentQueue} |
| */ |
| -AsyncUtil.Queue.prototype.cancel = function() { |
| - this.closures_ = []; |
| +AsyncUtil.Queue = function() { |
| + AsyncUtil.ConcurrentQueue.call(this, 1); |
| }; |
| +AsyncUtil.Queue.prototype.__proto__ = AsyncUtil.ConcurrentQueue.prototype; |
| + |
| /** |
| * Creates a class for executing several asynchronous closures in a group in |
| * a dependency order. |