Commit bc045e02 authored by fukino's avatar fukino Committed by Commit bot

Aggregate consequtive rescan request as much as possible.

- Revived AsyncUtil.Aggregation, which was used to aggregate consecutive run requests into one.
- Aggregated consecutive re-scan request using the aggregator described above.

BUG=316050
TEST=confirmed manually

Review URL: https://codereview.chromium.org/488043003

Cr-Commit-Position: refs/heads/master@{#291846}
parent 94a526a1
...@@ -254,6 +254,82 @@ AsyncUtil.Group.prototype.finish_ = function(task) { ...@@ -254,6 +254,82 @@ AsyncUtil.Group.prototype.finish_ = function(task) {
this.continue_(); this.continue_();
}; };
/**
* Aggregates consecutive calls and executes the closure only once instead of
* several times. The first call is always called immediately, and the next
* consecutive ones are aggregated and the closure is called only once once
* |delay| amount of time passes after the last call to run().
*
* @param {function()} closure Closure to be aggregated.
* @param {number=} opt_delay Minimum aggregation time in milliseconds. Default
* is 50 milliseconds.
* @constructor
*/
AsyncUtil.Aggregator = function(closure, opt_delay) {
/**
* @type {number}
* @private
*/
this.delay_ = opt_delay || 50;
/**
* @type {function()}
* @private
*/
this.closure_ = closure;
/**
* @type {number?}
* @private
*/
this.scheduledRunsTimer_ = null;
/**
* @type {number}
* @private
*/
this.lastRunTime_ = 0;
};
/**
* Runs a closure. Skips consecutive calls. The first call is called
* immediately.
*/
AsyncUtil.Aggregator.prototype.run = function() {
// If recently called, then schedule the consecutive call with a delay.
if (Date.now() - this.lastRunTime_ < this.delay_) {
this.cancelScheduledRuns_();
this.scheduledRunsTimer_ = setTimeout(this.runImmediately_.bind(this),
this.delay_ + 1);
this.lastRunTime_ = Date.now();
return;
}
// Otherwise, run immediately.
this.runImmediately_();
};
/**
* Calls the schedule immediately and cancels any scheduled calls.
* @private
*/
AsyncUtil.Aggregator.prototype.runImmediately_ = function() {
this.cancelScheduledRuns_();
this.closure_();
this.lastRunTime_ = Date.now();
};
/**
* Cancels all scheduled runs (if any).
* @private
*/
AsyncUtil.Aggregator.prototype.cancelScheduledRuns_ = function() {
if (this.scheduledRunsTimer_) {
clearTimeout(this.scheduledRunsTimer_);
this.scheduledRunsTimer_ = null;
}
};
/** /**
* Samples calls so that they are not called too frequently. * Samples calls so that they are not called too frequently.
* The first call is always called immediately, and the following calls may * The first call is always called immediately, and the following calls may
......
...@@ -33,6 +33,8 @@ function DirectoryModel(singleSelection, fileFilter, fileWatcher, ...@@ -33,6 +33,8 @@ function DirectoryModel(singleSelection, fileFilter, fileWatcher,
this.changeDirectorySequence_ = 0; this.changeDirectorySequence_ = 0;
this.directoryChangeQueue_ = new AsyncUtil.Queue(); this.directoryChangeQueue_ = new AsyncUtil.Queue();
this.rescanAggregator_ = new AsyncUtil.Aggregator(
this.rescanSoon.bind(this, true), 500);
this.fileFilter_ = fileFilter; this.fileFilter_ = fileFilter;
this.fileFilter_.addEventListener('changed', this.fileFilter_.addEventListener('changed',
...@@ -189,13 +191,13 @@ DirectoryModel.prototype.onWatcherDirectoryChanged_ = function(event) { ...@@ -189,13 +191,13 @@ DirectoryModel.prototype.onWatcherDirectoryChanged_ = function(event) {
}.bind(this)).catch(function(error) { }.bind(this)).catch(function(error) {
console.error('Error in proceeding the changed event.', error, console.error('Error in proceeding the changed event.', error,
'Fallback to force-refresh'); 'Fallback to force-refresh');
this.rescanSoon(true); this.rescanAggregator_.run();
}.bind(this)); }.bind(this));
} else { } else {
// Invokes force refresh if the detailed information isn't provided. // Invokes force refresh if the detailed information isn't provided.
// This can occur very frequently (e.g. when copying files into Downlaods) // This can occur very frequently (e.g. when copying files into Downlaods)
// and rescan is heavy operation, so we keep some interval for each rescan. // and rescan is heavy operation, so we keep some interval for each rescan.
this.rescanLater(true); this.rescanAggregator_.run();
} }
}; };
......
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