Commit 95a98a7d authored by Bo Majewski's avatar Bo Majewski Committed by Commit Bot

Renames ImageRequest to ImageRequestTask

During a cleanup https://codereview.chromium.org/1148563004 the image
Request class was renamed to ImageRequest. However, the file name was
kept as request.js. Make the class and its file name the same.

Bug: 903742
Change-Id: I6f2d7bbfb6f3f94001d0cd1e629fc27f83061c45
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245429Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Commit-Queue: Bo Majewski <majewski@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779705}
parent c18c02f9
...@@ -22,3 +22,7 @@ IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) { ...@@ -22,3 +22,7 @@ IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) {
IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderTest) { IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderTest) {
RunTestURL("image_loader_unittest_gen.html"); RunTestURL("image_loader_unittest_gen.html");
} }
IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, SchedulerTest) {
RunTestURL("scheduler_unittest_gen.html");
}
...@@ -14,9 +14,9 @@ js_type_check("closure_compile_module") { ...@@ -14,9 +14,9 @@ js_type_check("closure_compile_module") {
":image_loader", ":image_loader",
":image_loader_client", ":image_loader_client",
":image_loader_util", ":image_loader_util",
":image_request_task",
":load_image_request", ":load_image_request",
":piex_loader", ":piex_loader",
":request",
":scheduler", ":scheduler",
] ]
} }
...@@ -39,9 +39,9 @@ js_unittest("cache_unittest") { ...@@ -39,9 +39,9 @@ js_unittest("cache_unittest") {
js_library("image_loader") { js_library("image_loader") {
deps = [ deps = [
":cache", ":cache",
":image_request_task",
":load_image_request", ":load_image_request",
":piex_loader", ":piex_loader",
":request",
":scheduler", ":scheduler",
"//ui/file_manager/externs:file_manager_private", "//ui/file_manager/externs:file_manager_private",
] ]
...@@ -96,7 +96,7 @@ js_library("piex_loader") { ...@@ -96,7 +96,7 @@ js_library("piex_loader") {
externs_list = [ "//ui/file_manager/externs/platform.js" ] externs_list = [ "//ui/file_manager/externs/platform.js" ]
} }
js_library("request") { js_library("image_request_task") {
deps = [ deps = [
":cache", ":cache",
":image_loader_util", ":image_loader_util",
...@@ -108,7 +108,14 @@ js_library("request") { ...@@ -108,7 +108,14 @@ js_library("request") {
} }
js_library("scheduler") { js_library("scheduler") {
deps = [ ":request" ] deps = [ ":image_request_task" ]
}
js_unittest("scheduler_unittest") {
deps = [
":scheduler",
"//ui/webui/resources/js:webui_resource_test",
]
} }
js_test_gen_html("js_test_gen_html") { js_test_gen_html("js_test_gen_html") {
...@@ -117,6 +124,7 @@ js_test_gen_html("js_test_gen_html") { ...@@ -117,6 +124,7 @@ js_test_gen_html("js_test_gen_html") {
":cache_unittest", ":cache_unittest",
":image_loader_client_unittest", ":image_loader_client_unittest",
":image_loader_unittest", ":image_loader_unittest",
":scheduler_unittest",
] ]
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
// <include src="image_loader.js"> // <include src="image_loader.js">
// <include src="image_loader_util.js"> // <include src="image_loader_util.js">
// <include src="piex_loader.js"> // <include src="piex_loader.js">
// <include src="request.js"> // <include src="image_request_task.js">
// <include src="scheduler.js"> // <include src="scheduler.js">
// Entry point. // Entry point.
// <include src="background.js"> // <include src="background.js">
...@@ -131,7 +131,7 @@ ImageLoader.prototype.onMessage_ = function(senderOrigin, request, callback) { ...@@ -131,7 +131,7 @@ ImageLoader.prototype.onMessage_ = function(senderOrigin, request, callback) {
return false; // No callback calls. return false; // No callback calls.
} else { } else {
// Create a request task and add it to the scheduler (queue). // Create a request task and add it to the scheduler (queue).
const requestTask = new ImageRequest( const requestTask = new ImageRequestTask(
requestId, this.cache_, this.piexLoader_, request, callback); requestId, this.cache_, this.piexLoader_, request, callback);
this.scheduler_.add(requestTask); this.scheduler_.add(requestTask);
return true; // Request will call the callback. return true; // Request will call the callback.
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* @param {function(!LoadImageResponse)} callback Response handler. * @param {function(!LoadImageResponse)} callback Response handler.
* @constructor * @constructor
*/ */
function ImageRequest(id, cache, piexLoader, request, callback) { function ImageRequestTask(id, cache, piexLoader, request, callback) {
/** /**
* Global ID (concatenated client ID and client request ID). * Global ID (concatenated client ID and client request ID).
* @type {string} * @type {string}
...@@ -111,7 +111,7 @@ function ImageRequest(id, cache, piexLoader, request, callback) { ...@@ -111,7 +111,7 @@ function ImageRequest(id, cache, piexLoader, request, callback) {
* @const * @const
* @type {number} * @type {number}
*/ */
ImageRequest.VIDEO_THUMBNAIL_POSITION = 3; // [sec] ImageRequestTask.VIDEO_THUMBNAIL_POSITION = 3; // [sec]
/** /**
* The maximum milliseconds to load video. If loading video exceeds the limit, * The maximum milliseconds to load video. If loading video exceeds the limit,
...@@ -119,13 +119,13 @@ ImageRequest.VIDEO_THUMBNAIL_POSITION = 3; // [sec] ...@@ -119,13 +119,13 @@ ImageRequest.VIDEO_THUMBNAIL_POSITION = 3; // [sec]
* @const * @const
* @type {number} * @type {number}
*/ */
ImageRequest.MAX_MILLISECONDS_TO_LOAD_VIDEO = 3000; ImageRequestTask.MAX_MILLISECONDS_TO_LOAD_VIDEO = 3000;
/** /**
* A map which is used to estimate content type from extension. * A map which is used to estimate content type from extension.
* @enum {string} * @enum {string}
*/ */
ImageRequest.ExtensionContentTypeMap = { ImageRequestTask.ExtensionContentTypeMap = {
gif: 'image/gif', gif: 'image/gif',
png: 'image/png', png: 'image/png',
svg: 'image/svg', svg: 'image/svg',
...@@ -138,7 +138,7 @@ ImageRequest.ExtensionContentTypeMap = { ...@@ -138,7 +138,7 @@ ImageRequest.ExtensionContentTypeMap = {
* Returns ID of the request. * Returns ID of the request.
* @return {string} Request ID. * @return {string} Request ID.
*/ */
ImageRequest.prototype.getId = function() { ImageRequestTask.prototype.getId = function() {
return this.id_; return this.id_;
}; };
...@@ -146,7 +146,7 @@ ImageRequest.prototype.getId = function() { ...@@ -146,7 +146,7 @@ ImageRequest.prototype.getId = function() {
* Returns the client's task ID for the request. * Returns the client's task ID for the request.
* @return {number} * @return {number}
*/ */
ImageRequest.prototype.getClientTaskId = function() { ImageRequestTask.prototype.getClientTaskId = function() {
// Every incoming request should have been given a taskId. // Every incoming request should have been given a taskId.
assert(this.request_.taskId); assert(this.request_.taskId);
return this.request_.taskId; return this.request_.taskId;
...@@ -158,7 +158,7 @@ ImageRequest.prototype.getClientTaskId = function() { ...@@ -158,7 +158,7 @@ ImageRequest.prototype.getClientTaskId = function() {
* *
* @return {number} Priority. * @return {number} Priority.
*/ */
ImageRequest.prototype.getPriority = function() { ImageRequestTask.prototype.getPriority = function() {
return (this.request_.priority !== undefined) ? this.request_.priority : 2; return (this.request_.priority !== undefined) ? this.request_.priority : 2;
}; };
...@@ -169,7 +169,7 @@ ImageRequest.prototype.getPriority = function() { ...@@ -169,7 +169,7 @@ ImageRequest.prototype.getPriority = function() {
* @param {function()} onSuccess Success callback. * @param {function()} onSuccess Success callback.
* @param {function()} onFailure Failure callback. * @param {function()} onFailure Failure callback.
*/ */
ImageRequest.prototype.loadFromCacheAndProcess = function( ImageRequestTask.prototype.loadFromCacheAndProcess = function(
onSuccess, onFailure) { onSuccess, onFailure) {
this.loadFromCache_( this.loadFromCache_(
function(width, height, ifd, data) { // Found in cache. function(width, height, ifd, data) { // Found in cache.
...@@ -185,14 +185,14 @@ ImageRequest.prototype.loadFromCacheAndProcess = function( ...@@ -185,14 +185,14 @@ ImageRequest.prototype.loadFromCacheAndProcess = function(
* *
* @param {function()} callback Completion callback. * @param {function()} callback Completion callback.
*/ */
ImageRequest.prototype.downloadAndProcess = function(callback) { ImageRequestTask.prototype.downloadAndProcess = function(callback) {
if (this.downloadCallback_) { if (this.downloadCallback_) {
throw new Error('Downloading already started.'); throw new Error('Downloading already started.');
} }
this.downloadCallback_ = callback; this.downloadCallback_ = callback;
this.downloadOriginal_(this.onImageLoad_.bind(this), this.downloadOriginal_(
this.onImageError_.bind(this)); this.onImageLoad_.bind(this), this.onImageError_.bind(this));
}; };
/** /**
...@@ -203,7 +203,7 @@ ImageRequest.prototype.downloadAndProcess = function(callback) { ...@@ -203,7 +203,7 @@ ImageRequest.prototype.downloadAndProcess = function(callback) {
* @param {function()} onFailure Failure callback. * @param {function()} onFailure Failure callback.
* @private * @private
*/ */
ImageRequest.prototype.loadFromCache_ = function(onSuccess, onFailure) { ImageRequestTask.prototype.loadFromCache_ = function(onSuccess, onFailure) {
const cacheKey = LoadImageRequest.cacheKey(this.request_); const cacheKey = LoadImageRequest.cacheKey(this.request_);
if (!cacheKey) { if (!cacheKey) {
...@@ -238,7 +238,7 @@ ImageRequest.prototype.loadFromCache_ = function(onSuccess, onFailure) { ...@@ -238,7 +238,7 @@ ImageRequest.prototype.loadFromCache_ = function(onSuccess, onFailure) {
* @param {string} data Image data. * @param {string} data Image data.
* @private * @private
*/ */
ImageRequest.prototype.saveToCache_ = function(width, height, data) { ImageRequestTask.prototype.saveToCache_ = function(width, height, data) {
const timestamp = this.request_.timestamp; const timestamp = this.request_.timestamp;
if (!this.request_.cache || !timestamp) { if (!this.request_.cache || !timestamp) {
...@@ -262,7 +262,7 @@ ImageRequest.prototype.saveToCache_ = function(width, height, data) { ...@@ -262,7 +262,7 @@ ImageRequest.prototype.saveToCache_ = function(width, height, data) {
* @param {function()} onFailure Failure callback. * @param {function()} onFailure Failure callback.
* @private * @private
*/ */
ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) { ImageRequestTask.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
this.image_.onload = function() { this.image_.onload = function() {
URL.revokeObjectURL(this.image_.src); URL.revokeObjectURL(this.image_.src);
onSuccess(); onSuccess();
...@@ -324,9 +324,11 @@ ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) { ...@@ -324,9 +324,11 @@ ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
// Load video thumbnails by using video tag instead of XHR. // Load video thumbnails by using video tag instead of XHR.
if (fileType.type === 'video') { if (fileType.type === 'video') {
this.createVideoThumbnailUrl_(this.request_.url).then(function(url) { this.createVideoThumbnailUrl_(this.request_.url)
.then(function(url) {
this.image_.src = url; this.image_.src = url;
}.bind(this)).catch(function(error) { }.bind(this))
.catch(function(error) {
console.error('Video thumbnail error: ', error); console.error('Video thumbnail error: ', error);
onFailure(); onFailure();
}); });
...@@ -353,7 +355,7 @@ ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) { ...@@ -353,7 +355,7 @@ ImageRequest.prototype.downloadOriginal_ = function(onSuccess, onFailure) {
* thumbnail. * thumbnail.
* @private * @private
*/ */
ImageRequest.prototype.createVideoThumbnailUrl_ = function(url) { ImageRequestTask.prototype.createVideoThumbnailUrl_ = function(url) {
const video = const video =
assertInstanceof(document.createElement('video'), HTMLVideoElement); assertInstanceof(document.createElement('video'), HTMLVideoElement);
return Promise return Promise
...@@ -361,13 +363,13 @@ ImageRequest.prototype.createVideoThumbnailUrl_ = function(url) { ...@@ -361,13 +363,13 @@ ImageRequest.prototype.createVideoThumbnailUrl_ = function(url) {
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
video.addEventListener('canplay', resolve); video.addEventListener('canplay', resolve);
video.addEventListener('error', reject); video.addEventListener('error', reject);
video.currentTime = ImageRequest.VIDEO_THUMBNAIL_POSITION; video.currentTime = ImageRequestTask.VIDEO_THUMBNAIL_POSITION;
video.preload = 'auto'; video.preload = 'auto';
video.src = url; video.src = url;
video.load(); video.load();
}), }),
new Promise((resolve) => { new Promise((resolve) => {
setTimeout(resolve, ImageRequest.MAX_MILLISECONDS_TO_LOAD_VIDEO); setTimeout(resolve, ImageRequestTask.MAX_MILLISECONDS_TO_LOAD_VIDEO);
}).then(() => { }).then(() => {
// If we don't receive 'canplay' event after 3 seconds have passed for // If we don't receive 'canplay' event after 3 seconds have passed for
// some reason (e.g. unseekable video), we give up generating // some reason (e.g. unseekable video), we give up generating
...@@ -396,7 +398,7 @@ ImageRequest.prototype.createVideoThumbnailUrl_ = function(url) { ...@@ -396,7 +398,7 @@ ImageRequest.prototype.createVideoThumbnailUrl_ = function(url) {
* type and the fetched data. * type and the fetched data.
* @param {function()} onFailure Failure callback. * @param {function()} onFailure Failure callback.
*/ */
ImageRequest.prototype.load = function(url, onSuccess, onFailure) { ImageRequestTask.prototype.load = function(url, onSuccess, onFailure) {
this.aborted_ = false; this.aborted_ = false;
// Do not call any callbacks when aborting. // Do not call any callbacks when aborting.
...@@ -405,7 +407,8 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) { ...@@ -405,7 +407,8 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) {
// When content type is not available, try to estimate it from url. // When content type is not available, try to estimate it from url.
if (!contentType) { if (!contentType) {
contentType = contentType =
ImageRequest.ExtensionContentTypeMap[this.extractExtension_(url)]; ImageRequestTask
.ExtensionContentTypeMap[this.extractExtension_(url)];
} }
if (!this.aborted_) { if (!this.aborted_) {
...@@ -422,7 +425,8 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) { ...@@ -422,7 +425,8 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) {
// The query parameter is workaround for crbug.com/379678, which forces the // The query parameter is workaround for crbug.com/379678, which forces the
// browser to obtain the latest contents of the image. // browser to obtain the latest contents of the image.
const noCacheUrl = url + '?nocache=' + Date.now(); const noCacheUrl = url + '?nocache=' + Date.now();
this.xhr_ = ImageRequest.load_(noCacheUrl, onMaybeSuccess, onMaybeFailure); this.xhr_ =
ImageRequestTask.load_(noCacheUrl, onMaybeSuccess, onMaybeFailure);
}; };
/** /**
...@@ -430,7 +434,7 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) { ...@@ -430,7 +434,7 @@ ImageRequest.prototype.load = function(url, onSuccess, onFailure) {
* @param {string} url Url. * @param {string} url Url.
* @return {string} Extracted extension, e.g. png. * @return {string} Extracted extension, e.g. png.
*/ */
ImageRequest.prototype.extractExtension_ = function(url) { ImageRequestTask.prototype.extractExtension_ = function(url) {
const result = (/\.([a-zA-Z]+)$/i).exec(url); const result = (/\.([a-zA-Z]+)$/i).exec(url);
return result ? result[1] : ''; return result ? result[1] : '';
}; };
...@@ -446,7 +450,7 @@ ImageRequest.prototype.extractExtension_ = function(url) { ...@@ -446,7 +450,7 @@ ImageRequest.prototype.extractExtension_ = function(url) {
* @return {XMLHttpRequest} XHR instance. * @return {XMLHttpRequest} XHR instance.
* @private * @private
*/ */
ImageRequest.load_ = function(url, onSuccess, onFailure) { ImageRequestTask.load_ = function(url, onSuccess, onFailure) {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.responseType = 'blob'; xhr.responseType = 'blob';
...@@ -481,7 +485,7 @@ ImageRequest.load_ = function(url, onSuccess, onFailure) { ...@@ -481,7 +485,7 @@ ImageRequest.load_ = function(url, onSuccess, onFailure) {
* @param {boolean} imageChanged Whether the image has been changed. * @param {boolean} imageChanged Whether the image has been changed.
* @private * @private
*/ */
ImageRequest.prototype.sendImage_ = function(imageChanged) { ImageRequestTask.prototype.sendImage_ = function(imageChanged) {
let width; let width;
let height; let height;
let data; let data;
...@@ -525,7 +529,7 @@ ImageRequest.prototype.sendImage_ = function(imageChanged) { ...@@ -525,7 +529,7 @@ ImageRequest.prototype.sendImage_ = function(imageChanged) {
* @param {string} data Image data. * @param {string} data Image data.
* @private * @private
*/ */
ImageRequest.prototype.sendImageData_ = function(width, height, data) { ImageRequestTask.prototype.sendImageData_ = function(width, height, data) {
const result = {width, height, ifd: this.ifd_, data}; const result = {width, height, ifd: this.ifd_, data};
this.sendResponse_(new LoadImageResponse( this.sendResponse_(new LoadImageResponse(
LoadImageResponseStatus.SUCCESS, this.getClientTaskId(), result)); LoadImageResponseStatus.SUCCESS, this.getClientTaskId(), result));
...@@ -536,7 +540,7 @@ ImageRequest.prototype.sendImageData_ = function(width, height, data) { ...@@ -536,7 +540,7 @@ ImageRequest.prototype.sendImageData_ = function(width, height, data) {
* and finalizes the request process. * and finalizes the request process.
* @private * @private
*/ */
ImageRequest.prototype.onImageLoad_ = function() { ImageRequestTask.prototype.onImageLoad_ = function() {
// Perform processing if the url is not a data url, or if there are some // Perform processing if the url is not a data url, or if there are some
// operations requested. // operations requested.
if (!(this.request_.url.match(/^data/) || if (!(this.request_.url.match(/^data/) ||
...@@ -559,7 +563,7 @@ ImageRequest.prototype.onImageLoad_ = function() { ...@@ -559,7 +563,7 @@ ImageRequest.prototype.onImageLoad_ = function() {
* finalizes the request process. * finalizes the request process.
* @private * @private
*/ */
ImageRequest.prototype.onImageError_ = function() { ImageRequestTask.prototype.onImageError_ = function() {
this.sendResponse_(new LoadImageResponse( this.sendResponse_(new LoadImageResponse(
LoadImageResponseStatus.ERROR, this.getClientTaskId())); LoadImageResponseStatus.ERROR, this.getClientTaskId()));
this.cleanup_(); this.cleanup_();
...@@ -569,7 +573,7 @@ ImageRequest.prototype.onImageError_ = function() { ...@@ -569,7 +573,7 @@ ImageRequest.prototype.onImageError_ = function() {
/** /**
* Cancels the request. * Cancels the request.
*/ */
ImageRequest.prototype.cancel = function() { ImageRequestTask.prototype.cancel = function() {
this.cleanup_(); this.cleanup_();
// If downloading has started, then call the callback. // If downloading has started, then call the callback.
...@@ -582,7 +586,7 @@ ImageRequest.prototype.cancel = function() { ...@@ -582,7 +586,7 @@ ImageRequest.prototype.cancel = function() {
* Cleans up memory used by this request. * Cleans up memory used by this request.
* @private * @private
*/ */
ImageRequest.prototype.cleanup_ = function() { ImageRequestTask.prototype.cleanup_ = function() {
this.image_.onerror = function() {}; this.image_.onerror = function() {};
this.image_.onload = function() {}; this.image_.onload = function() {};
......
...@@ -3,43 +3,44 @@ ...@@ -3,43 +3,44 @@
// found in the LICENSE file. // found in the LICENSE file.
/** /**
* Scheduler for requests. Fetches requests from a queue and processes them * Scheduler for ImageRequestTask objects. Fetches tasks from a queue and
* synchronously, taking into account priorities. The highest priority is 0. * processes them synchronously, taking into account priorities. The highest
* priority is 0.
* @constructor * @constructor
*/ */
function Scheduler() { function Scheduler() {
/** /**
* List of requests waiting to be checked. If these items are available in * List of tasks waiting to be checked. If these items are available in
* cache, then they are processed immediately after starting the scheduler. * cache, then they are processed immediately after starting the scheduler.
* However, if they have to be downloaded, then these requests are moved * However, if they have to be downloaded, then these tasks are moved
* to pendingRequests_. * to pendingTasks_.
* *
* @type {Array<ImageRequest>} * @type {Array<ImageRequestTask>}
* @private * @private
*/ */
this.newRequests_ = []; this.newTasks_ = [];
/** /**
* List of pending requests for images to be downloaded. * List of pending tasks for images to be downloaded.
* @type {Array<ImageRequest>} * @type {Array<ImageRequestTask>}
* @private * @private
*/ */
this.pendingRequests_ = []; this.pendingTasks_ = [];
/** /**
* List of requests being processed. * List of tasks being processed.
* @type {Array<ImageRequest>} * @type {Array<ImageRequestTask>}
* @private * @private
*/ */
this.activeRequests_ = []; this.activeTasks_ = [];
/** /**
* Map of requests being added to the queue, but not finalized yet. Keyed by * Map of tasks being added to the queue, but not finalized yet. Keyed by
* the ImageRequest id. * the ImageRequestTask id.
* @type {Object<string, ImageRequest>}> * @type {Object<string, ImageRequestTask>}>
* @private * @private
*/ */
this.requests_ = {}; this.tasks_ = {};
/** /**
* If the scheduler has been started. * If the scheduler has been started.
...@@ -50,121 +51,119 @@ function Scheduler() { ...@@ -50,121 +51,119 @@ function Scheduler() {
} }
/** /**
* Maximum download requests to be run in parallel. * Maximum download tasks to be run in parallel.
* @type {number} * @type {number}
* @const * @const
*/ */
Scheduler.MAXIMUM_IN_PARALLEL = 5; Scheduler.MAXIMUM_IN_PARALLEL = 5;
/** /**
* Adds a request to the internal priority queue and executes it when requests * 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 * with higher priorities are finished. If the result is cached, then it is
* processed immediately once the scheduler is started. * processed immediately once the scheduler is started.
* *
* @param {ImageRequest} request Request object. * @param {ImageRequestTask} task A task to be run
*/ */
Scheduler.prototype.add = function(request) { Scheduler.prototype.add = function(task) {
if (!this.started_) { if (!this.started_) {
this.newRequests_.push(request); this.newTasks_.push(task);
this.requests_[request.getId()] = request; this.tasks_[task.getId()] = task;
return; return;
} }
// Enqueue the request, since already started. // Enqueue the tasks, since already started.
this.pendingRequests_.push(request); this.pendingTasks_.push(task);
this.sortPendingRequests_(); this.sortPendingTasks_();
this.continue_(); this.continue_();
}; };
/** /**
* Removes a request from the scheduler (if exists). * Removes a task from the scheduler (if exists).
* @param {string} requestId Unique ID of the request. * @param {string} taskId Unique ID of the task.
*/ */
Scheduler.prototype.remove = function(requestId) { Scheduler.prototype.remove = function(taskId) {
const request = this.requests_[requestId]; const task = this.tasks_[taskId];
if (!request) { if (!task) {
return; return;
} }
// Remove from the internal queues with pending tasks. // Remove from the internal queues with pending tasks.
const newIndex = this.pendingRequests_.indexOf(request); const newIndex = this.newTasks_.indexOf(task);
if (newIndex != -1) { if (newIndex != -1) {
this.newRequests_.splice(newIndex, 1); this.newTasks_.splice(newIndex, 1);
} }
const pendingIndex = this.pendingRequests_.indexOf(request); const pendingIndex = this.pendingTasks_.indexOf(task);
if (pendingIndex != -1) { if (pendingIndex != -1) {
this.pendingRequests_.splice(pendingIndex, 1); this.pendingTasks_.splice(pendingIndex, 1);
} }
// Cancel the request. // Cancel the task.
request.cancel(); task.cancel();
delete this.requests_[requestId]; delete this.tasks_[taskId];
}; };
/** /**
* Starts handling requests. * Starts handling tasks.
*/ */
Scheduler.prototype.start = function() { Scheduler.prototype.start = function() {
this.started_ = true; this.started_ = true;
// Process tasks added before scheduler has been started. // Process tasks added before scheduler has been started.
this.pendingRequests_ = this.newRequests_; this.pendingTasks_ = this.newTasks_;
this.sortPendingRequests_(); this.sortPendingTasks_();
this.newRequests_ = []; this.newTasks_ = [];
// Start serving enqueued requests. // Start serving enqueued tasks.
this.continue_(); this.continue_();
}; };
/** /**
* Sorts pending requests by priorities. * Sorts pending tasks by priorities.
* @private * @private
*/ */
Scheduler.prototype.sortPendingRequests_ = function() { Scheduler.prototype.sortPendingTasks_ = function() {
this.pendingRequests_.sort(function(a, b) { this.pendingTasks_.sort(function(a, b) {
return a.getPriority() - b.getPriority(); return a.getPriority() - b.getPriority();
}); });
}; };
/** /**
* Processes pending requests from the queue. There is no guarantee that * Processes pending tasks from the queue. There is no guarantee that
* all of the tasks will be processed at once. * all of the tasks will be processed at once.
* *
* @private * @private
*/ */
Scheduler.prototype.continue_ = function() { Scheduler.prototype.continue_ = function() {
// Run only up to MAXIMUM_IN_PARALLEL in the same time. // Run only up to MAXIMUM_IN_PARALLEL in the same time.
while (this.pendingRequests_.length && while (this.pendingTasks_.length &&
this.activeRequests_.length < Scheduler.MAXIMUM_IN_PARALLEL) { this.activeTasks_.length < Scheduler.MAXIMUM_IN_PARALLEL) {
const request = this.pendingRequests_.shift(); const task = this.pendingTasks_.shift();
this.activeRequests_.push(request); this.activeTasks_.push(task);
// Try to load from cache. If doesn't exist, then download. // Try to load from cache. If doesn't exist, then download.
request.loadFromCacheAndProcess( task.loadFromCacheAndProcess(
this.finish_.bind(this, request), this.finish_.bind(this, task), function(currentTask) {
function(currentRequest) { currentTask.downloadAndProcess(this.finish_.bind(this, currentTask));
currentRequest.downloadAndProcess( }.bind(this, task));
this.finish_.bind(this, currentRequest));
}.bind(this, request));
} }
}; };
/** /**
* Handles finished requests. * Handles finished tasks.
* *
* @param {ImageRequest} request Finished request. * @param {ImageRequestTask} task Finished task.
* @private * @private
*/ */
Scheduler.prototype.finish_ = function(request) { Scheduler.prototype.finish_ = function(task) {
const index = this.activeRequests_.indexOf(request); const index = this.activeTasks_.indexOf(task);
if (index < 0) { if (index < 0) {
console.warn('Request not found.'); console.warn('ImageRequestTask not found.');
} }
this.activeRequests_.splice(index, 1); this.activeTasks_.splice(index, 1);
delete this.requests_[request.getId()]; delete this.tasks_[task.getId()];
// Continue handling the most important requests (if started). // Continue handling the most important tasks (if started).
if (this.started_) { if (this.started_) {
this.continue_(); this.continue_();
} }
......
// Copyright 2020 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.
'use strict';
/**
* Fake global clock used to record the "time" at which a task was run.
*/
let globalTime = 0;
function setUp() {
globalTime = 0;
}
/**
* @typedef{{
* cancelCallCount: number,
* runTime: number,
* }}
*/
let FakeImageRequestTask;
/**
* @param {string} taskId
* @return {!FakeImageRequestTask}
*/
function newTask(taskId, priority) {
return /** @type !FakeImageRequestTask */ ({
// Counts how many times cancel method was called.
// Used to test multiple cancellation of the same task.
cancelCallCount: 0,
// Records value of globalTime variable at the time the main method,
// loadFromCacheAndProcess is called. Used to test if the task was
// executed and in what orders tasks were executed.
runTime: 0,
getId() {
return taskId;
},
getPriority() {
return priority;
},
cancel() {
++this.cancelCallCount;
},
loadFromCacheAndProcess(resolve, reject) {
this.runTime = ++globalTime;
setTimeout(resolve);
},
});
}
/**
* Checks that adding and removing tasks before the scheduler is started works.
*/
function testIdleSchedulerAddRemove() {
const scheduler = new Scheduler();
const fakeTask = newTask('task-1', 0);
scheduler.add(/** @type {!ImageRequestTask} */ (fakeTask));
assertEquals(0, fakeTask.cancelCallCount);
scheduler.remove('task-1');
assertEquals(1, fakeTask.cancelCallCount);
scheduler.remove('task-1');
assertEquals(1, fakeTask.cancelCallCount);
}
/**
* Checks that tasks that were in newTasks are correctly copied to pending
* tasks when scheduler is started. They also should be executed in the
* order of their priorities.
*/
function testNewTasksMovedAndRunInPriorityOrder() {
const fakeTask1 = newTask('task-1', 1);
const fakeTask2 = newTask('task-2', 0);
const scheduler = new Scheduler();
scheduler.add(/** @type {!ImageRequestTask} */ (fakeTask1));
scheduler.add(/** @type {!ImageRequestTask} */ (fakeTask2));
scheduler.start();
assertEquals(2, fakeTask1.runTime);
assertEquals(1, fakeTask2.runTime);
}
/**
* Checks that the scheduler only launches MAXIMUM_IN_PARALLEL tasks.
*/
function testParallelTasks() {
const scheduler = new Scheduler();
const taskList = [];
for (let i = 0; i <= Scheduler.MAXIMUM_IN_PARALLEL; ++i) {
taskList.push(newTask(`task-${i}`, 0));
scheduler.add(/** @type {!ImageRequestTask} */ (taskList[i]));
}
scheduler.start();
for (let i = 0; i < Scheduler.MAXIMUM_IN_PARALLEL; ++i) {
assertEquals(i + 1, taskList[i].runTime, `task ${i} did not run`);
}
assertEquals(0, taskList[Scheduler.MAXIMUM_IN_PARALLEL].runTime);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment