OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * Namespace for async utility functions. | 8 * Namespace for async utility functions. |
9 */ | 9 */ |
10 var AsyncUtil = {}; | 10 var AsyncUtil = {}; |
(...skipping 25 matching lines...) Expand all Loading... |
36 callback(iterationCompletionCallback, element, index, array); | 36 callback(iterationCompletionCallback, element, index, array); |
37 }.bind(null, array[i], i)); | 37 }.bind(null, array[i], i)); |
38 } | 38 } |
39 queue.run(function(iterationCompletionCallback) { | 39 queue.run(function(iterationCompletionCallback) { |
40 completionCallback(); // Don't pass iteration completion callback. | 40 completionCallback(); // Don't pass iteration completion callback. |
41 }); | 41 }); |
42 }; | 42 }; |
43 | 43 |
44 /** | 44 /** |
45 * Creates a class for executing several asynchronous closures in a fifo queue. | 45 * Creates a class for executing several asynchronous closures in a fifo queue. |
| 46 * Added tasks will be started in order they were added. Tasks are run |
| 47 * concurrently. At most, |limit| jobs will be run at the same time. |
| 48 * |
| 49 * @param {number} limit The number of jobs to run at the same time. |
| 50 * @constructor |
| 51 */ |
| 52 AsyncUtil.ConcurrentQueue = function(limit) { |
| 53 console.assert(limit > 0, '|limit| must be larger than 0'); |
| 54 |
| 55 this.limit_ = limit; |
| 56 this.addedTasks_ = []; |
| 57 this.pendingTasks_ = []; |
| 58 this.isCancelled_ = false; |
| 59 |
| 60 Object.seal(this); |
| 61 }; |
| 62 |
| 63 /** |
| 64 * @return {boolean} True when a task is running, otherwise false. |
| 65 */ |
| 66 AsyncUtil.ConcurrentQueue.prototype.isRunning = function() { |
| 67 return this.pendingTasks_.length !== 0; |
| 68 }; |
| 69 |
| 70 /** |
| 71 * @return {number} Number of waiting tasks. |
| 72 */ |
| 73 AsyncUtil.ConcurrentQueue.prototype.getWaitingTasksCount = function() { |
| 74 return this.addedTasks_.length; |
| 75 }; |
| 76 |
| 77 /** |
| 78 * @return {boolean} Number of running tasks. |
| 79 */ |
| 80 AsyncUtil.ConcurrentQueue.prototype.getRunningTasksCount = function() { |
| 81 return this.pendingTasks_.length; |
| 82 }; |
| 83 |
| 84 /** |
| 85 * Enqueues a closure to be executed. |
| 86 * @param {function(function())} closure Closure with a completion |
| 87 * callback to be executed. |
| 88 */ |
| 89 AsyncUtil.ConcurrentQueue.prototype.run = function(closure) { |
| 90 if (this.isCancelled_) { |
| 91 console.error('Queue is calcelled. Cannot add a new task.'); |
| 92 return; |
| 93 } |
| 94 |
| 95 this.addedTasks_.push(closure); |
| 96 this.continue_(); |
| 97 }; |
| 98 |
| 99 /** |
| 100 * Cancels the queue. It removes all the not-run (yet) tasks. Note that this |
| 101 * does NOT stop tasks currently running. |
| 102 */ |
| 103 AsyncUtil.ConcurrentQueue.prototype.cancel = function() { |
| 104 this.isCancelled_ = true; |
| 105 this.addedTasks_ = []; |
| 106 }; |
| 107 |
| 108 /** |
| 109 * @return {boolean} True when the queue have been requested to cancel or is |
| 110 * already cancelled. Otherwise false. |
| 111 */ |
| 112 AsyncUtil.ConcurrentQueue.prototype.isCancelled = function() { |
| 113 return this.isCancelled_; |
| 114 }; |
| 115 |
| 116 /** |
| 117 * Runs the next tasks if available. |
| 118 * @private |
| 119 */ |
| 120 AsyncUtil.ConcurrentQueue.prototype.continue_ = function() { |
| 121 if (this.addedTasks_.length === 0) |
| 122 return; |
| 123 |
| 124 console.assert( |
| 125 this.pendingTasks_.length <= this.limit_, |
| 126 'Too many jobs are running (' + this.pendingTasks_.length + ')'); |
| 127 |
| 128 if (this.pendingTasks_.length >= this.limit_) |
| 129 return; |
| 130 |
| 131 // Run the next closure. |
| 132 var closure = this.addedTasks_.shift(); |
| 133 this.pendingTasks_.push(closure); |
| 134 closure(this.onTaskFinished_.bind(this, closure)); |
| 135 |
| 136 this.continue_(); |
| 137 }; |
| 138 |
| 139 /** |
| 140 * Called when a task is finished. Removes the tasks from pending task list. |
| 141 * @param {function()} closure Finished task, which has been bound in |
| 142 * |continue_|. |
| 143 * @private |
| 144 */ |
| 145 AsyncUtil.ConcurrentQueue.prototype.onTaskFinished_ = function(closure) { |
| 146 var index = this.pendingTasks_.indexOf(closure); |
| 147 console.assert(index >= 0, 'Invalid task is finished'); |
| 148 this.pendingTasks_.splice(index, 1); |
| 149 |
| 150 this.continue_(); |
| 151 }; |
| 152 |
| 153 /** |
| 154 * Creates a class for executing several asynchronous closures in a fifo queue. |
46 * Added tasks will be executed sequentially in order they were added. | 155 * Added tasks will be executed sequentially in order they were added. |
47 * | 156 * |
48 * @constructor | 157 * @constructor |
| 158 * @extends {AsyncUtil.ConcurrentQueue} |
49 */ | 159 */ |
50 AsyncUtil.Queue = function() { | 160 AsyncUtil.Queue = function() { |
51 this.running_ = false; | 161 AsyncUtil.ConcurrentQueue.call(this, 1); |
52 this.closures_ = []; | |
53 }; | 162 }; |
54 | 163 |
55 /** | 164 AsyncUtil.Queue.prototype.__proto__ = AsyncUtil.ConcurrentQueue.prototype; |
56 * @return {boolean} True when a task is running, otherwise false. | |
57 */ | |
58 AsyncUtil.Queue.prototype.isRunning = function() { | |
59 return this.running_; | |
60 }; | |
61 | |
62 /** | |
63 * Enqueues a closure to be executed. | |
64 * @param {function(function())} closure Closure with a completion callback to | |
65 * be executed. | |
66 */ | |
67 AsyncUtil.Queue.prototype.run = function(closure) { | |
68 this.closures_.push(closure); | |
69 if (!this.running_) | |
70 this.continue_(); | |
71 }; | |
72 | |
73 /** | |
74 * Serves the next closure from the queue. | |
75 * @private | |
76 */ | |
77 AsyncUtil.Queue.prototype.continue_ = function() { | |
78 if (!this.closures_.length) { | |
79 this.running_ = false; | |
80 return; | |
81 } | |
82 | |
83 // Run the next closure. | |
84 this.running_ = true; | |
85 var closure = this.closures_.shift(); | |
86 closure(this.continue_.bind(this)); | |
87 }; | |
88 | |
89 /** | |
90 * Cancels all pending tasks. Note that this does NOT cancel the task running | |
91 * currently. | |
92 */ | |
93 AsyncUtil.Queue.prototype.cancel = function() { | |
94 this.closures_ = []; | |
95 }; | |
96 | 165 |
97 /** | 166 /** |
98 * Creates a class for executing several asynchronous closures in a group in | 167 * Creates a class for executing several asynchronous closures in a group in |
99 * a dependency order. | 168 * a dependency order. |
100 * | 169 * |
101 * @constructor | 170 * @constructor |
102 */ | 171 */ |
103 AsyncUtil.Group = function() { | 172 AsyncUtil.Group = function() { |
104 this.addedTasks_ = {}; | 173 this.addedTasks_ = {}; |
105 this.pendingTasks_ = {}; | 174 this.pendingTasks_ = {}; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 /** | 322 /** |
254 * Cancels all scheduled runs (if any). | 323 * Cancels all scheduled runs (if any). |
255 * @private | 324 * @private |
256 */ | 325 */ |
257 AsyncUtil.Aggregation.prototype.cancelScheduledRuns_ = function() { | 326 AsyncUtil.Aggregation.prototype.cancelScheduledRuns_ = function() { |
258 if (this.scheduledRunsTimer_) { | 327 if (this.scheduledRunsTimer_) { |
259 clearTimeout(this.scheduledRunsTimer_); | 328 clearTimeout(this.scheduledRunsTimer_); |
260 this.scheduledRunsTimer_ = null; | 329 this.scheduledRunsTimer_ = null; |
261 } | 330 } |
262 }; | 331 }; |
OLD | NEW |