123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- import {ImageRequestTask} from './image_request_task.js';
- /**
- * Scheduler for ImageRequestTask objects. Fetches tasks from a queue and
- * processes them synchronously, taking into account priorities. The highest
- * priority is 0.
- * @constructor
- */
- export function Scheduler() {
- /**
- * List of tasks waiting to be checked. If these items are available in
- * cache, then they are processed immediately after starting the scheduler.
- * However, if they have to be downloaded, then these tasks are moved
- * to pendingTasks_.
- *
- * @type {Array<ImageRequestTask>}
- * @private
- */
- this.newTasks_ = [];
- /**
- * List of pending tasks for images to be downloaded.
- * @type {Array<ImageRequestTask>}
- * @private
- */
- this.pendingTasks_ = [];
- /**
- * List of tasks being processed.
- * @type {Array<ImageRequestTask>}
- * @private
- */
- this.activeTasks_ = [];
- /**
- * Map of tasks being added to the queue, but not finalized yet. Keyed by
- * the ImageRequestTask id.
- * @type {Object<string, ImageRequestTask>}>
- * @private
- */
- this.tasks_ = {};
- /**
- * If the scheduler has been started.
- * @type {boolean}
- * @private
- */
- this.started_ = false;
- }
- /**
- * Maximum download tasks to be run in parallel.
- * @type {number}
- * @const
- */
- Scheduler.MAXIMUM_IN_PARALLEL = 5;
- /**
- * Adds a task to the internal priority queue and executes it when tasks
- * with higher priorities are finished. If the result is cached, then it is
- * processed immediately once the scheduler is started.
- *
- * @param {ImageRequestTask} task A task to be run
- */
- Scheduler.prototype.add = function(task) {
- if (!this.started_) {
- this.newTasks_.push(task);
- this.tasks_[task.getId()] = task;
- return;
- }
- // Enqueue the tasks, since already started.
- this.pendingTasks_.push(task);
- this.sortPendingTasks_();
- this.continue_();
- };
- /**
- * Removes a task from the scheduler (if exists).
- * @param {string} taskId Unique ID of the task.
- */
- Scheduler.prototype.remove = function(taskId) {
- const task = this.tasks_[taskId];
- if (!task) {
- return;
- }
- // Remove from the internal queues with pending tasks.
- const newIndex = this.newTasks_.indexOf(task);
- if (newIndex != -1) {
- this.newTasks_.splice(newIndex, 1);
- }
- const pendingIndex = this.pendingTasks_.indexOf(task);
- if (pendingIndex != -1) {
- this.pendingTasks_.splice(pendingIndex, 1);
- }
- // Cancel the task.
- task.cancel();
- delete this.tasks_[taskId];
- };
- /**
- * Starts handling tasks.
- */
- Scheduler.prototype.start = function() {
- this.started_ = true;
- // Process tasks added before scheduler has been started.
- this.pendingTasks_ = this.newTasks_;
- this.sortPendingTasks_();
- this.newTasks_ = [];
- // Start serving enqueued tasks.
- this.continue_();
- };
- /**
- * Sorts pending tasks by priorities.
- * @private
- */
- Scheduler.prototype.sortPendingTasks_ = function() {
- this.pendingTasks_.sort(function(a, b) {
- return a.getPriority() - b.getPriority();
- });
- };
- /**
- * Processes pending tasks from the queue. There is no guarantee that
- * all of the tasks will be processed at once.
- *
- * @private
- */
- Scheduler.prototype.continue_ = function() {
- // Run only up to MAXIMUM_IN_PARALLEL in the same time.
- while (this.pendingTasks_.length &&
- this.activeTasks_.length < Scheduler.MAXIMUM_IN_PARALLEL) {
- const task = this.pendingTasks_.shift();
- this.activeTasks_.push(task);
- // Try to load from cache. If doesn't exist, then download.
- task.loadFromCacheAndProcess(
- this.finish_.bind(this, task), function(currentTask) {
- currentTask.downloadAndProcess(this.finish_.bind(this, currentTask));
- }.bind(this, task));
- }
- };
- /**
- * Handles finished tasks.
- *
- * @param {ImageRequestTask} task Finished task.
- * @private
- */
- Scheduler.prototype.finish_ = function(task) {
- const index = this.activeTasks_.indexOf(task);
- if (index < 0) {
- console.warn('ImageRequestTask not found.');
- }
- this.activeTasks_.splice(index, 1);
- delete this.tasks_[task.getId()];
- // Continue handling the most important tasks (if started).
- if (this.started_) {
- this.continue_();
- }
- };
|