Merge "Add a PromisePrioritizer and use it for notifications fetching"

This commit is contained in:
jenkins-bot 2016-06-27 17:42:41 +00:00 committed by Gerrit Code Review
commit 1cca7453b3
4 changed files with 94 additions and 6 deletions

View file

@ -196,6 +196,7 @@ $wgResourceModules += array(
'ext.echo.api' => $echoResourceTemplate + array(
'scripts' => array(
'api/mw.echo.api.js',
'api/mw.echo.api.PromisePrioritizer.js',
'api/mw.echo.api.EchoApi.js',
'api/mw.echo.api.APIHandler.js',
'api/mw.echo.api.LocalAPIHandler.js',

View file

@ -15,6 +15,7 @@
this.fetchingPromise = null;
this.limit = config.limit || 25;
this.fetchingPrioritizer = new mw.echo.api.PromisePrioritizer();
};
OO.initClass( mw.echo.api.EchoApi );
@ -147,13 +148,13 @@
return $.Deferred().reject().promise();
}
return handler.fetchNotifications(
return this.fetchingPrioritizer.prioritize( handler.fetchNotifications(
type,
// For the remote source, we are fetching 'local' notifications
'local',
!!isForced,
this.convertFiltersToAPIParams( filters )
)
) )
.then( function ( result ) {
return OO.getProp( result.query, 'notifications' );
} );
@ -177,12 +178,12 @@
[ sources ] :
'local';
return this.network.getApiHandler( 'local' ).fetchNotifications(
return this.fetchingPrioritizer.prioritize( this.network.getApiHandler( 'local' ).fetchNotifications(
type,
sources,
isForced,
this.convertFiltersToAPIParams( filters )
)
) )
.then( function ( result ) {
return OO.getProp( result.query, 'notifications' );
} );

View file

@ -0,0 +1,88 @@
( function ( mw, $ ) {
/**
* Promise prioritizer for API actions. The prioritizer takes
* a promise at a time, always prioritizing the latest promise and
* aborting and ignoring the others.
*
* This allows us to send multiple promises in quick successions but
* trust that we get back only the latest successful request.
*
* @class
*
* @constructor
*/
mw.echo.api.PromisePrioritizer = function MwEchoApiPromisePrioritizer() {
this.deferred = $.Deferred();
this.promise = null;
};
/* Initialization */
OO.initClass( mw.echo.api.PromisePrioritizer );
/**
* Prioritize a promise
*
* @param {jQuery.Promise|Promise} promise Promise
* @return {jQuery.Promise} The main deferred object that resolves
* or rejects when the latest promise is resolved or rejected.
*/
mw.echo.api.PromisePrioritizer.prototype.prioritize = function ( promise ) {
var previousPromise = this.promise;
promise
.then(
this.setSuccess.bind( this, promise ),
this.setFailure.bind( this, promise )
);
this.promise = promise;
if ( previousPromise && previousPromise.abort ) {
previousPromise.abort();
}
return this.deferred.promise();
};
/**
* Set success for the promise. Resolve the main deferred object only
* if we are dealing with the currently prioritized promise.
*
* @param {jQuery.Promise} promise The promise that resolved successfully.
* The main deferred object is resolved with the result of the
* latest prioritized promise.
*/
mw.echo.api.PromisePrioritizer.prototype.setSuccess = function ( promise ) {
var prioritizer = this;
if ( this.promise === promise ) {
this.promise.done( function () {
prioritizer.deferred.resolve.apply( prioritizer.deferred, arguments );
prioritizer.promise = null;
prioritizer.deferred = $.Deferred();
} );
}
};
/**
* Set failure for the promise. Reject the main deferred object only
* if we are dealing with the currently prioritized promise.
*
* @param {jQuery.Promise} promise The promise that failed.
* The main deferred object is rejected with the result of the
* latest prioritized promise
*/
mw.echo.api.PromisePrioritizer.prototype.setFailure = function ( promise ) {
var prioritizer = this;
if ( this.promise === promise ) {
this.promise.fail( function () {
prioritizer.deferred.reject.apply( prioritizer.deferred, arguments );
prioritizer.promise = null;
prioritizer.deferred = $.Deferred();
} );
}
};
} )( mediaWiki, jQuery );

View file

@ -205,7 +205,6 @@
*/
mw.echo.ui.NotificationsInboxWidget.prototype.pushPending = function () {
this.noticeMessageWidget.toggle( false );
this.readStateSelectWidget.setDisabled( true );
this.topPaginationWidget.setDisabled( true );
this.bottomPaginationWidget.setDisabled( true );
@ -218,7 +217,6 @@
*/
mw.echo.ui.NotificationsInboxWidget.prototype.popPending = function () {
this.resetMessageLabel();
this.readStateSelectWidget.setDisabled( false );
this.topPaginationWidget.setDisabled( false );
this.bottomPaginationWidget.setDisabled( false );