Safely generate cached conversation props on startup

This commit is contained in:
Scott Nonnenberg 2020-08-11 16:15:06 -07:00 committed by GitHub
parent b32445cd20
commit 67058e27bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 13 deletions

View file

@ -169,11 +169,11 @@
this.typingPauseTimer = null;
// Keep props ready
const generateProps = () => {
this.generateProps = () => {
this.cachedProps = this.getProps();
};
this.on('change', generateProps);
generateProps();
this.on('change', this.generateProps);
this.generateProps();
},
isMe() {
@ -444,6 +444,14 @@
return this.cachedProps;
},
getProps() {
// This is to prevent race conditions on startup; Conversation models are created
// but the full ConversationController.load() sequence isn't complete. So, we
// don't cache props on create, but we do later when load() calls generateProps()
// for us.
if (!window.ConversationController.isFetchComplete()) {
return null;
}
const color = this.getColor();
const typingValues = _.values(this.contactTypingTimers || {});

View file

@ -664,10 +664,7 @@
return ConversationController.get(identifier);
},
getConversation() {
// This needs to be an unsafe call, because this method is called during
// initial module setup. We may be in the middle of the initial fetch to
// the database.
return ConversationController.getUnsafe(this.get('conversationId'));
return ConversationController.get(this.get('conversationId'));
},
createNonBreakingLastSeparator(text) {
if (!text) {

View file

@ -91,10 +91,6 @@ export class ConversationController {
// This function takes null just fine. Backbone typings are too restrictive.
return this._conversations.get(id as string);
}
// Needed for some model setup which happens during the initial fetch() call below
getUnsafe(id: string) {
return this._conversations.get(id);
}
dangerouslyCreateAndAdd(attributes: Partial<ConversationModelType>) {
return this._conversations.add(attributes);
}
@ -617,6 +613,9 @@ export class ConversationController {
this._initialFetchComplete = false;
this._conversations.reset([]);
}
isFetchComplete() {
return this._initialFetchComplete;
}
async load() {
window.log.info('ConversationController: starting initial fetch');
@ -636,6 +635,12 @@ export class ConversationController {
await Promise.all(
this._conversations.map(async conversation => {
// This call is important to allow Conversation models not to generate their
// cached props on initial construction if we're in the middle of the load
// from the database. Then we come back to the models when it is safe and
// generate those props.
conversation.generateProps();
if (!conversation.get('lastMessage')) {
await conversation.updateLastMessage();
}

1
ts/model-types.d.ts vendored
View file

@ -85,6 +85,7 @@ declare class ConversationModelType extends Backbone.Model<
cleanup(): Promise<void>;
disableProfileSharing(): void;
dropProfileKey(): Promise<void>;
generateProps(): void;
getAccepted(): boolean;
getAvatarPath(): string | undefined;
getColor(): ColorType | undefined;

View file

@ -203,11 +203,27 @@
"reasonCategory": "usageTrusted",
"updated": "2020-03-25T15:45:04.024Z"
},
{
"rule": "jQuery-load(",
"path": "js/models/conversations.js",
"line": " // but the full ConversationController.load() sequence isn't complete. So, we",
"lineNumber": 448,
"reasonCategory": "exampleCode",
"updated": "2020-08-11T21:28:50.868Z"
},
{
"rule": "jQuery-load(",
"path": "js/models/conversations.js",
"line": " // don't cache props on create, but we do later when load() calls generateProps()",
"lineNumber": 449,
"reasonCategory": "exampleCode",
"updated": "2020-08-11T21:28:50.868Z"
},
{
"rule": "jQuery-wrap(",
"path": "js/models/conversations.js",
"line": " await wrap(",
"lineNumber": 665,
"lineNumber": 673,
"reasonCategory": "falseMatch",
"updated": "2020-06-09T20:26:46.515Z"
},