try filling async instead of sync in scroll handler

see if that avoids jumps
pull/21833/head
Bruno Windels 2019-03-26 12:19:30 +01:00
parent 8f7170a4a1
commit 18b5041ed2
1 changed files with 40 additions and 9 deletions

View File

@ -21,7 +21,7 @@ import { KeyCode } from '../../Keyboard';
import Timer from '../../utils/Timer'; import Timer from '../../utils/Timer';
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
const DEBUG_SCROLL = false; const DEBUG_SCROLL = true;
// The amount of extra scroll distance to allow prior to unfilling. // The amount of extra scroll distance to allow prior to unfilling.
// See _getExcessHeight. // See _getExcessHeight.
@ -193,10 +193,10 @@ module.exports = React.createClass({
debuglog("onScroll", this._getScrollNode().scrollTop); debuglog("onScroll", this._getScrollNode().scrollTop);
this._scrollTimeout.restart(); this._scrollTimeout.restart();
this._saveScrollState(); this._saveScrollState();
this.checkFillState();
this.updatePreventShrinking(); this.updatePreventShrinking();
console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()})); console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()}));
this.props.onScroll(ev); this.props.onScroll(ev);
this.checkFillState();
}, },
onResize: function() { onResize: function() {
@ -270,11 +270,12 @@ module.exports = React.createClass({
}, },
// check the scroll state and send out backfill requests if necessary. // check the scroll state and send out backfill requests if necessary.
checkFillState: function() { checkFillState: async function(depth=0) {
if (this.unmounted) { if (this.unmounted) {
return; return;
} }
const isFirstCall = depth === 0;
const sn = this._getScrollNode(); const sn = this._getScrollNode();
// if there is less than a screenful of messages above or below the // if there is less than a screenful of messages above or below the
@ -301,16 +302,46 @@ module.exports = React.createClass({
// `---------' - // `---------' -
// //
if (isFirstCall) {
if (this._isFilling) {
debuglog("_isFilling: not entering while request is ongoing, marking for a subsequent request");
this._fillRequestWhileRunning = true;
return;
}
debuglog("_isFilling: setting");
this._isFilling = true;
}
const contentHeight = this._getMessagesHeight(); const contentHeight = this._getMessagesHeight();
const contentTop = contentHeight - this._getListHeight(); const contentTop = contentHeight - this._getListHeight();
const contentScrollTop = sn.scrollTop + contentTop; const contentScrollTop = sn.scrollTop + contentTop;
const fillPromises = [];
if (contentScrollTop < sn.clientHeight) { if (contentScrollTop < sn.clientHeight) {
// need to back-fill // need to back-fill
this._maybeFill(true); fillPromises.push(this._maybeFill(depth, true));
} }
if (contentScrollTop > contentHeight - sn.clientHeight * 2) { if (contentScrollTop > contentHeight - sn.clientHeight * 2) {
// need to forward-fill // need to forward-fill
this._maybeFill(false); fillPromises.push(this._maybeFill(depth, false));
}
if (fillPromises.length) {
try {
await Promise.all(fillPromises);
} catch (err) {
console.error(err);
}
}
if (isFirstCall) {
debuglog("_isFilling: clearing");
this._isFilling = false;
}
if (this._fillRequestWhileRunning) {
this._fillRequestWhileRunning = false;
this.checkFillState();
} }
}, },
@ -364,7 +395,7 @@ module.exports = React.createClass({
}, },
// check if there is already a pending fill request. If not, set one off. // check if there is already a pending fill request. If not, set one off.
_maybeFill: function(backwards) { _maybeFill: function(depth, backwards) {
const dir = backwards ? 'b' : 'f'; const dir = backwards ? 'b' : 'f';
if (this._pendingFillRequests[dir]) { if (this._pendingFillRequests[dir]) {
debuglog("Already a "+dir+" fill in progress - not starting another"); debuglog("Already a "+dir+" fill in progress - not starting another");
@ -377,7 +408,7 @@ module.exports = React.createClass({
// events) so make sure we set this before firing off the call. // events) so make sure we set this before firing off the call.
this._pendingFillRequests[dir] = true; this._pendingFillRequests[dir] = true;
Promise.try(() => { return new Promise(resolve => setTimeout(resolve, 1)).then(() => {
return this.props.onFillRequest(backwards); return this.props.onFillRequest(backwards);
}).finally(() => { }).finally(() => {
this._pendingFillRequests[dir] = false; this._pendingFillRequests[dir] = false;
@ -393,9 +424,9 @@ module.exports = React.createClass({
// further pagination requests have been disabled until now, so // further pagination requests have been disabled until now, so
// it's time to check the fill state again in case the pagination // it's time to check the fill state again in case the pagination
// was insufficient. // was insufficient.
this.checkFillState(); return this.checkFillState(depth + 1);
} }
}).done(); });
}, },
/* get the current scroll state. This returns an object with the following /* get the current scroll state. This returns an object with the following