diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index b21e97c6c5..4946e2c61e 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -41,6 +41,7 @@ var Resend = require("../../Resend"); var SlashCommands = require("../../SlashCommands"); var dis = require("../../dispatcher"); var Tinter = require("../../Tinter"); +var rate_limited_func = require('../../ratelimitedfunc'); var PAGINATE_SIZE = 20; var INITIAL_SIZE = 20; @@ -617,7 +618,7 @@ module.exports = React.createClass({ } }, - _updateTabCompleteList: function(room) { + _updateTabCompleteList: new rate_limited_func(function(room) { if (!room || !this.tabComplete) { return; } @@ -626,7 +627,7 @@ module.exports = React.createClass({ CommandEntry.fromCommands(SlashCommands.getCommandList()) ) ); - }, + }, 500), _initialiseMessagePanel: function() { var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index f2f0b03234..c2431e78ac 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -22,6 +22,7 @@ var Modal = require("../../../Modal"); var Entities = require("../../../Entities"); var sdk = require('../../../index'); var GeminiScrollbar = require('react-gemini-scrollbar'); +var rate_limited_func = require('../../../ratelimitedfunc'); var INITIAL_LOAD_NUM_MEMBERS = 30; var SHARE_HISTORY_WARNING = "Newly invited users will see the history of this room. "+ @@ -147,14 +148,14 @@ module.exports = React.createClass({ } }, - _updateList: function() { + _updateList: new rate_limited_func(function() { this.memberDict = this.getMemberDict(); var self = this; this.setState({ members: self.roomMembers() }); - }, + }, 500), onInvite: function(inputText) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index bb54e1e500..722fa23f34 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -24,6 +24,7 @@ var RoomListSorter = require("../../../RoomListSorter"); var Unread = require('../../../Unread'); var dis = require("../../../dispatcher"); var sdk = require('../../../index'); +var rate_limited_func = require('../../../ratelimitedfunc'); var HIDE_CONFERENCE_CHANS = true; @@ -155,36 +156,9 @@ module.exports = React.createClass({ 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 - } - } - } - }, + _delayedRefreshRoomList: new rate_limited_func(function() { + this.refreshRoomList(); + }, 500), refreshRoomList: function() { // console.log("DEBUG: Refresh room list delta=%s ms", diff --git a/src/ratelimitedfunc.js b/src/ratelimitedfunc.js new file mode 100644 index 0000000000..f7cf165414 --- /dev/null +++ b/src/ratelimitedfunc.js @@ -0,0 +1,39 @@ +/* +Copyright 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +module.exports = function(f, min_interval_ms) { + this.lastCall = 0; + this.scheduledCall = undefined; + + var self = this; + return function() { + var now = Date.now(); + + if (self.lastCall < now - min_interval_ms) { + f.apply(this); + self.lastCall = now; + } else if (self.scheduledCall === undefined) { + self.scheduledCall = setTimeout(() => { + self.scheduledCall = undefined; + f.apply(this); + self.lastCall = now; + }, + (self.lastCall + min_interval_ms) - now + ); + } + }; +}; +