Improve perf of refreshing room list. Show spinner when loading left rooms.
When the JS SDK encounters a new room it will emit a flurry of events for things like state and room members. Refreshing the room list on each event is bad for performance. This is okay initially because the room list is only shown after the first sync, but when getting archived rooms it locks up for 15-30s as it thrashes. Add a 1s cap to refreshRoomList() which means that it will refresh *AT MOST* once every second. If it has been >1s since the last refresh it will immediately refresh. If it has been <1s it will wait the difference.
This commit is contained in:
parent
22635f251d
commit
711fdd25af
1 changed files with 49 additions and 6 deletions
|
@ -38,6 +38,7 @@ module.exports = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
activityMap: null,
|
activityMap: null,
|
||||||
|
isLoadingLeftRooms: false,
|
||||||
lists: {},
|
lists: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -89,20 +90,24 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoom: function(room) {
|
onRoom: function(room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeleteRoom: function(roomId) {
|
onDeleteRoom: function(roomId) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onArchivedHeaderClick: function(isHidden) {
|
onArchivedHeaderClick: function(isHidden) {
|
||||||
if (!isHidden) {
|
if (!isHidden) {
|
||||||
|
var self = this;
|
||||||
|
this.setState({ isLoadingLeftRooms: true });
|
||||||
// we don't care about the response since it comes down via "Room"
|
// we don't care about the response since it comes down via "Room"
|
||||||
// events.
|
// events.
|
||||||
MatrixClientPeg.get().syncLeftRooms().catch(function(err) {
|
MatrixClientPeg.get().syncLeftRooms().catch(function(err) {
|
||||||
console.error("Failed to sync left rooms: %s", err);
|
console.error("Failed to sync left rooms: %s", err);
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
}).finally(function() {
|
||||||
|
self.setState({ isLoadingLeftRooms: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -143,22 +148,57 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomName: function(room) {
|
onRoomName: function(room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomTags: function(event, room) {
|
onRoomTags: function(event, room) {
|
||||||
this.refreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomStateEvents: function(ev, state) {
|
onRoomStateEvents: function(ev, state) {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomMemberName: function(ev, member) {
|
onRoomMemberName: function(ev, member) {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
this._delayedRefreshRoomList();
|
||||||
|
},
|
||||||
|
|
||||||
|
_delayedRefreshRoomList: function() {
|
||||||
|
// There can be 1000s of JS SDK events when rooms are initially synced;
|
||||||
|
// we don't want to do lots of work rendering until things have settled.
|
||||||
|
// Therefore, keep a 1s refresh buffer which will refresh the room list
|
||||||
|
// at MOST once every 1s to prevent thrashing.
|
||||||
|
var MAX_REFRESH_INTERVAL_MS = 1000;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!self._lastRefreshRoomListTs) {
|
||||||
|
self.refreshRoomList(); // first refresh evar
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var timeWaitedMs = Date.now() - self._lastRefreshRoomListTs;
|
||||||
|
if (timeWaitedMs > MAX_REFRESH_INTERVAL_MS) {
|
||||||
|
clearTimeout(self._refreshRoomListTimerId);
|
||||||
|
self._refreshRoomListTimerId = null;
|
||||||
|
self.refreshRoomList(); // refreshed more than MAX_REFRESH_INTERVAL_MS ago
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// refreshed less than MAX_REFRESH_INTERVAL_MS ago, wait the difference
|
||||||
|
// if we aren't already waiting. If we are waiting then NOP, it will
|
||||||
|
// fire soon, promise!
|
||||||
|
if (!self._refreshRoomListTimerId) {
|
||||||
|
self._refreshRoomListTimerId = setTimeout(function() {
|
||||||
|
self.refreshRoomList();
|
||||||
|
}, 10 + MAX_REFRESH_INTERVAL_MS - timeWaitedMs); // 10 is a buffer amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshRoomList: function() {
|
refreshRoomList: function() {
|
||||||
|
// console.log("DEBUG: Refresh room list delta=%s ms",
|
||||||
|
// (!this._lastRefreshRoomListTs ? "-" : (Date.now() - this._lastRefreshRoomListTs))
|
||||||
|
// );
|
||||||
|
|
||||||
// TODO: rather than bluntly regenerating and re-sorting everything
|
// TODO: rather than bluntly regenerating and re-sorting everything
|
||||||
// every time we see any kind of room change from the JS SDK
|
// every time we see any kind of room change from the JS SDK
|
||||||
// we could do incremental updates on our copy of the state
|
// we could do incremental updates on our copy of the state
|
||||||
|
@ -166,6 +206,7 @@ module.exports = React.createClass({
|
||||||
// us re-rendering all the sublists every time anything changes anywhere
|
// us re-rendering all the sublists every time anything changes anywhere
|
||||||
// in the state of the client.
|
// in the state of the client.
|
||||||
this.setState(this.getRoomLists());
|
this.setState(this.getRoomLists());
|
||||||
|
this._lastRefreshRoomListTs = Date.now();
|
||||||
},
|
},
|
||||||
|
|
||||||
getRoomLists: function() {
|
getRoomLists: function() {
|
||||||
|
@ -320,6 +361,8 @@ module.exports = React.createClass({
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
alwaysShowHeader={ true }
|
alwaysShowHeader={ true }
|
||||||
|
startAsHidden={ true }
|
||||||
|
showSpinner={ self.state.isLoadingLeftRooms }
|
||||||
onHeaderClick= { self.onArchivedHeaderClick } />
|
onHeaderClick= { self.onArchivedHeaderClick } />
|
||||||
</div>
|
</div>
|
||||||
</GeminiScrollbar>
|
</GeminiScrollbar>
|
||||||
|
|
Loading…
Reference in a new issue