From 9056d68fc93679c288a1ca333701acc0ca674422 Mon Sep 17 00:00:00 2001 From: nimbleghost <132819643+nimbleghost@users.noreply.github.com> Date: Wed, 24 May 2023 17:48:39 +0200 Subject: [PATCH 1/4] Make async for loops performant using Promise.all --- web/src/app/Poller.js | 19 +++++----- web/src/app/SubscriptionManager.js | 57 ++++++++++++++---------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/web/src/app/Poller.js b/web/src/app/Poller.js index b956821..372e46e 100644 --- a/web/src/app/Poller.js +++ b/web/src/app/Poller.js @@ -21,15 +21,16 @@ class Poller { async pollAll() { console.log(`[Poller] Polling all subscriptions`); const subscriptions = await subscriptionManager.all(); - for (const s of subscriptions) { - try { - // TODO(eslint): Switch to Promise.all - // eslint-disable-next-line no-await-in-loop - await this.poll(s); - } catch (e) { - console.log(`[Poller] Error polling ${s.id}`, e); - } - } + + await Promise.all( + subscriptions.map(async (s) => { + try { + await this.poll(s); + } catch (e) { + console.log(`[Poller] Error polling ${s.id}`, e); + } + }) + ); } async poll(subscription) { diff --git a/web/src/app/SubscriptionManager.js b/web/src/app/SubscriptionManager.js index 7762753..03617e0 100644 --- a/web/src/app/SubscriptionManager.js +++ b/web/src/app/SubscriptionManager.js @@ -5,13 +5,12 @@ class SubscriptionManager { /** All subscriptions, including "new count"; this is a JOIN, see https://dexie.org/docs/API-Reference#joining */ async all() { const subscriptions = await db.subscriptions.toArray(); - await Promise.all( - subscriptions.map(async (s) => { - // eslint-disable-next-line no-param-reassign - s.new = await db.notifications.where({ subscriptionId: s.id, new: 1 }).count(); - }) + return Promise.all( + subscriptions.map(async (s) => ({ + ...s, + new: await db.notifications.where({ subscriptionId: s.id, new: 1 }).count(), + })) ); - return subscriptions; } async get(subscriptionId) { @@ -40,33 +39,31 @@ class SubscriptionManager { console.log(`[SubscriptionManager] Syncing subscriptions from remote`, remoteSubscriptions); // Add remote subscriptions - const remoteIds = []; // = topicUrl(baseUrl, topic) - for (let i = 0; i < remoteSubscriptions.length; i += 1) { - const remote = remoteSubscriptions[i]; - // TODO(eslint): Switch to Promise.all - // eslint-disable-next-line no-await-in-loop - const local = await this.add(remote.base_url, remote.topic, false); - const reservation = remoteReservations?.find((r) => remote.base_url === config.base_url && remote.topic === r.topic) || null; - // TODO(eslint): Switch to Promise.all - // eslint-disable-next-line no-await-in-loop - await this.update(local.id, { - displayName: remote.display_name, // May be undefined - reservation, // May be null! - }); - remoteIds.push(local.id); - } + const remoteIds = await Promise.all( + remoteSubscriptions.map(async (remote) => { + const local = await this.add(remote.base_url, remote.topic, false); + const reservation = remoteReservations?.find((r) => remote.base_url === config.base_url && remote.topic === r.topic) || null; + + await this.update(local.id, { + displayName: remote.display_name, // May be undefined + reservation, // May be null! + }); + + return local.id; + }) + ); // Remove local subscriptions that do not exist remotely const localSubscriptions = await db.subscriptions.toArray(); - for (let i = 0; i < localSubscriptions.length; i += 1) { - const local = localSubscriptions[i]; - const remoteExists = remoteIds.includes(local.id); - if (!local.internal && !remoteExists) { - // TODO(eslint): Switch to Promise.all - // eslint-disable-next-line no-await-in-loop - await this.remove(local.id); - } - } + + await Promise.all( + localSubscriptions.map(async (local) => { + const remoteExists = remoteIds.includes(local.id); + if (!local.internal && !remoteExists) { + await this.remove(local.id); + } + }) + ); } async updateState(subscriptionId, state) { From 4d90e32fe9f584b056fceea763aae2a39ea10396 Mon Sep 17 00:00:00 2001 From: nimbleghost <132819643+nimbleghost@users.noreply.github.com> Date: Wed, 24 May 2023 17:49:04 +0200 Subject: [PATCH 2/4] Use es6 destructuring swap for shuffling --- web/src/app/utils.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/web/src/app/utils.js b/web/src/app/utils.js index 0af1033..481d603 100644 --- a/web/src/app/utils.js +++ b/web/src/app/utils.js @@ -139,17 +139,14 @@ export const maybeAppendActionErrors = (message, notification) => { }; export const shuffle = (arr) => { - let j; - let x; - for (let index = arr.length - 1; index > 0; index -= 1) { - j = Math.floor(Math.random() * (index + 1)); - x = arr[index]; - // eslint-disable-next-line no-param-reassign - arr[index] = arr[j]; - // eslint-disable-next-line no-param-reassign - arr[j] = x; + const returnArr = [...arr]; + + for (let index = returnArr.length - 1; index > 0; index -= 1) { + const j = Math.floor(Math.random() * (index + 1)); + [returnArr[index], returnArr[j]] = [returnArr[j], returnArr[index]]; } - return arr; + + return returnArr; }; export const splitNoEmpty = (s, delimiter) => From d178be7576ea152386f9b41591df969eb6f18f29 Mon Sep 17 00:00:00 2001 From: nimbleghost <132819643+nimbleghost@users.noreply.github.com> Date: Wed, 24 May 2023 18:08:59 +0200 Subject: [PATCH 3/4] Fix param reassignment issue --- web/src/app/SubscriptionManager.js | 9 ++++++--- web/src/components/Notifications.jsx | 11 +++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/web/src/app/SubscriptionManager.js b/web/src/app/SubscriptionManager.js index 03617e0..ecbe4da 100644 --- a/web/src/app/SubscriptionManager.js +++ b/web/src/app/SubscriptionManager.js @@ -105,9 +105,12 @@ class SubscriptionManager { return false; } try { - // eslint-disable-next-line no-param-reassign - notification.new = 1; // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation - await db.notifications.add({ ...notification, subscriptionId }); // FIXME consider put() for double tab + await db.notifications.add({ + ...notification, + subscriptionId, + // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation + new: 1, + }); // FIXME consider put() for double tab await db.subscriptions.update(subscriptionId, { last: notification.id, }); diff --git a/web/src/components/Notifications.jsx b/web/src/components/Notifications.jsx index 7d4da06..2faf2fd 100644 --- a/web/src/components/Notifications.jsx +++ b/web/src/components/Notifications.jsx @@ -436,15 +436,10 @@ const ACTION_LABEL_SUFFIX = { }; const updateActionStatus = (notification, action, progress, error) => { - // TODO(eslint): Fix by spreading? Does the code depend on the change, though? - // eslint-disable-next-line no-param-reassign - notification.actions = notification.actions.map((a) => { - if (a.id !== action.id) { - return a; - } - return { ...a, progress, error }; + subscriptionManager.updateNotification({ + ...notification, + actions: notification.actions.map((a) => (a.id === action.id ? { ...a, progress, error } : a)), }); - subscriptionManager.updateNotification(notification); }; const performHttpAction = async (notification, action) => { From da17e4ee8a9c0c6f954a61fdab581a32fb887c1b Mon Sep 17 00:00:00 2001 From: nimbleghost <132819643+nimbleghost@users.noreply.github.com> Date: Wed, 24 May 2023 20:47:19 +0200 Subject: [PATCH 4/4] Make small code style improvements --- web/src/app/ConnectionManager.js | 4 +--- web/src/app/utils.js | 4 ++-- web/src/components/EmojiPicker.jsx | 12 +----------- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/web/src/app/ConnectionManager.js b/web/src/app/ConnectionManager.js index 751c7bd..2033cbe 100644 --- a/web/src/app/ConnectionManager.js +++ b/web/src/app/ConnectionManager.js @@ -61,9 +61,7 @@ class ConnectionManager { const { connectionId } = subscription; const added = !this.connections.get(connectionId); if (added) { - const { baseUrl } = subscription; - const { topic } = subscription; - const { user } = subscription; + const { baseUrl, topic, user } = subscription; const since = subscription.last; const connection = new Connection( connectionId, diff --git a/web/src/app/utils.js b/web/src/app/utils.js index 481d603..ab7551b 100644 --- a/web/src/app/utils.js +++ b/web/src/app/utils.js @@ -118,10 +118,10 @@ export const maybeWithBearerAuth = (headers, token) => { export const withBasicAuth = (headers, username, password) => ({ ...headers, Authorization: basicAuth(username, password) }); export const maybeWithAuth = (headers, user) => { - if (user && user.password) { + if (user?.password) { return withBasicAuth(headers, user.username, user.password); } - if (user && user.token) { + if (user?.token) { return withBearerAuth(headers, user.token); } return headers; diff --git a/web/src/components/EmojiPicker.jsx b/web/src/components/EmojiPicker.jsx index f9e8b5e..d1fb170 100644 --- a/web/src/components/EmojiPicker.jsx +++ b/web/src/components/EmojiPicker.jsx @@ -127,17 +127,7 @@ const Category = (props) => { ); }; -const emojiMatches = (emoji, words) => { - if (words.length === 0) { - return true; - } - for (const word of words) { - if (emoji.searchBase.indexOf(word) === -1) { - return false; - } - } - return true; -}; +const emojiMatches = (emoji, words) => words.length === 0 || words.some((word) => emoji.searchBase.includes(word)); const Emoji = (props) => { const { emoji } = props;